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