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_SOC_FAMILY_NORDIC_NRF) || \
32 defined(CONFIG_SOC_SERIES_IMXRT6XX)
33 /*
34 * DWT frequency is taken directly from the
35 * System Core clock (CPU) frequency, if the
36 * CMSIS SystemCoreClock symbols is available.
37 */
38 SystemCoreClockUpdate();
39
40 return SystemCoreClock;
41 #elif defined(CONFIG_CORTEX_M_SYSTICK)
42 /* SysTick and DWT both run at CPU frequency,
43 * reflected in the system timer HW cycles/sec.
44 */
45 return sys_clock_hw_cycles_per_sec();
46 #else
47 static uint64_t dwt_frequency;
48 uint32_t cyc_start, cyc_end;
49 uint64_t dwt_start, dwt_end;
50 uint64_t cyc_freq = sys_clock_hw_cycles_per_sec();
51 uint64_t dcyc, ddwt;
52
53 if (!dwt_frequency) {
54
55 z_arm_dwt_init();
56
57 do {
58 cyc_start = k_cycle_get_32();
59 dwt_start = z_arm_dwt_get_cycles();
60
61 k_busy_wait(10 * USEC_PER_MSEC);
62
63 cyc_end = k_cycle_get_32();
64 dwt_end = z_arm_dwt_get_cycles();
65
66 /*
67 * cycles are in 32-bit, and delta must be
68 * calculated in 32-bit precision. Or it would be
69 * wrapping around in 64-bit.
70 */
71 dcyc = (uint32_t)cyc_end - (uint32_t)cyc_start;
72
73 ddwt = dwt_end - dwt_start;
74 } while ((dcyc == 0) || (ddwt == 0));
75
76 dwt_frequency = (cyc_freq * ddwt) / dcyc;
77
78 }
79 return dwt_frequency;
80 #endif /* CONFIG_SOC_FAMILY_NORDIC_NRF */
81 }
82
arch_timing_init(void)83 void arch_timing_init(void)
84 {
85 z_arm_dwt_init();
86 z_arm_dwt_init_cycle_counter();
87 }
88
arch_timing_start(void)89 void arch_timing_start(void)
90 {
91 z_arm_dwt_cycle_count_start();
92 }
93
arch_timing_stop(void)94 void arch_timing_stop(void)
95 {
96 DWT->CTRL &= ~DWT_CTRL_CYCCNTENA_Msk;
97 }
98
arch_timing_counter_get(void)99 timing_t arch_timing_counter_get(void)
100 {
101 return (timing_t)z_arm_dwt_get_cycles();
102 }
103
arch_timing_cycles_get(volatile timing_t * const start,volatile timing_t * const end)104 uint64_t arch_timing_cycles_get(volatile timing_t *const start,
105 volatile timing_t *const end)
106 {
107 return (*end - *start);
108 }
109
arch_timing_freq_get(void)110 uint64_t arch_timing_freq_get(void)
111 {
112 return z_arm_dwt_freq_get();
113 }
114
arch_timing_cycles_to_ns(uint64_t cycles)115 uint64_t arch_timing_cycles_to_ns(uint64_t cycles)
116 {
117 return (cycles) * (NSEC_PER_USEC) / arch_timing_freq_get_mhz();
118 }
119
arch_timing_cycles_to_ns_avg(uint64_t cycles,uint32_t count)120 uint64_t arch_timing_cycles_to_ns_avg(uint64_t cycles, uint32_t count)
121 {
122 return arch_timing_cycles_to_ns(cycles) / count;
123 }
124
arch_timing_freq_get_mhz(void)125 uint32_t arch_timing_freq_get_mhz(void)
126 {
127 return (uint32_t)(arch_timing_freq_get() / 1000000U);
128 }
129