Skip to content

Commit 394d291

Browse files
ioannisgMaureenHelm
authored andcommitted
arch: arm: cortex-m: implement timing.c based on DWT
For Cortex-M platforms with DWT we implement the timing API (timing.c). Signed-off-by: Ioannis Glaropoulos <[email protected]>
1 parent 61d1d2e commit 394d291

File tree

4 files changed

+183
-0
lines changed

4 files changed

+183
-0
lines changed

arch/arm/core/aarch32/cortex_m/CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ zephyr_library_sources(
1515

1616
zephyr_library_sources_ifdef(CONFIG_DEBUG_COREDUMP coredump.c)
1717

18+
if(CONFIG_CORTEX_M_DWT)
19+
if (CONFIG_TIMING_FUNCTIONS)
20+
zephyr_library_sources(timing.c)
21+
endif()
22+
endif()
23+
1824
if (CONFIG_SW_VECTOR_RELAY)
1925
if (CONFIG_CPU_CORTEX_M_HAS_VTOR)
2026
set(relay_vector_table_sort_key relay_vectors)

arch/arm/core/aarch32/cortex_m/Kconfig

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,13 @@ config SW_VECTOR_RELAY_CLIENT
288288
sure the vector table pointer in RAM is set properly by the image upon
289289
initialization.
290290

291+
config CORTEX_M_DWT
292+
bool "Enable and use the DWT"
293+
depends on CPU_CORTEX_M_HAS_DWT
294+
default y if TIMING_FUNCTIONS
295+
help
296+
Enable and use the Data Watchpoint and Trace (DWT) unit for
297+
timing functions.
291298
endmenu
292299

293300
rsource "mpu/Kconfig"
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
/*
2+
* Copyright (c) 2020 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
/**
8+
* @file
9+
* @brief ARM Cortex-M Timing functions interface based on DWT
10+
*
11+
*/
12+
13+
#include <init.h>
14+
#include <timing/timing.h>
15+
#include <arch/arm/aarch32/cortex_m/cmsis.h>
16+
17+
18+
/**
19+
* @brief Initialize and Enable the DWT cycle counter
20+
*
21+
* This routine enables the cycle counter and initializes its value to zero.
22+
*
23+
* @return 0
24+
*/
25+
static inline int z_arm_dwt_init(struct device *arg)
26+
{
27+
/* Enable tracing */
28+
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
29+
30+
/* Clear and enable the cycle counter */
31+
DWT->CYCCNT = 0;
32+
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
33+
34+
/* Assert that the cycle counter is indeed implemented. */
35+
__ASSERT(DWT->CTRL & DWT_CTRL_NOCYCCNT_Msk != 0,
36+
"DWT implements no cycle counter. "
37+
"Cannot be used for cycle counting\n");
38+
39+
return 0;
40+
}
41+
42+
/**
43+
* @brief Return the current value of the cycle counter
44+
*
45+
* This routine returns the current value of the DWT Cycle Counter (DWT.CYCCNT)
46+
*
47+
* @return the cycle counter value
48+
*/
49+
static inline uint32_t z_arm_dwt_get_cycles(void)
50+
{
51+
return DWT->CYCCNT;
52+
}
53+
54+
/**
55+
* @brief Reset and start the DWT cycle counter
56+
*
57+
* This routine starts the cycle counter and resets its value to zero.
58+
*
59+
* @return 0
60+
*/
61+
static inline void z_arm_dwt_cycle_count_start(void)
62+
{
63+
DWT->CYCCNT = 0;
64+
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
65+
}
66+
67+
/**
68+
* @brief Return the current frequency of the cycle counter
69+
*
70+
* This routine returns the current frequency of the DWT Cycle Counter
71+
* in DWT cycles per second (Hz).
72+
*
73+
* @return the cycle counter frequency value
74+
*/
75+
static inline uint64_t z_arm_dwt_freq_get(void)
76+
{
77+
#if defined(CONFIG_SOC_FAMILY_NRF)
78+
/*
79+
* DWT frequency is taken directly from the
80+
* System Core clock (CPU) frequency, if the
81+
* CMSIS SystemCoreClock symbols is available.
82+
*/
83+
SystemCoreClockUpdate();
84+
85+
return SystemCoreClock;
86+
#elif defined(CONFIG_CORTEX_M_SYSTICK)
87+
/* SysTick and DWT both run at CPU frequency,
88+
* reflected in the system timer HW cycles/sec.
89+
*/
90+
return CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC;
91+
#else
92+
static uint64_t dwt_frequency;
93+
94+
if (!dwt_frequency) {
95+
96+
z_arm_dwt_init(NULL);
97+
98+
uint32_t cyc_start = k_cycle_get_32();
99+
uint64_t dwt_start = z_arm_dwt_get_cycles();
100+
101+
k_busy_wait(10 * USEC_PER_MSEC);
102+
103+
uint32_t cyc_end = k_cycle_get_32();
104+
uint64_t dwt_end = z_arm_dwt_get_cycles();
105+
106+
uint64_t cyc_freq = sys_clock_hw_cycles_per_sec();
107+
108+
/*
109+
* cycles are in 32-bit, and delta must be
110+
* calculated in 32-bit percision. Or it would
111+
* wrapping around in 64-bit.
112+
*/
113+
uint64_t dcyc = (uint32_t)cyc_end - (uint32_t)cyc_start;
114+
115+
uint64_t dtsc = dwt_end - dwt_start;
116+
117+
dwt_frequency = (cyc_freq * dtsc) / dcyc;
118+
119+
}
120+
return dwt_frequency;
121+
#endif /* CONFIG_SOC_FAMILY_NRF */
122+
}
123+
124+
void timing_init(void)
125+
{
126+
z_arm_dwt_init(NULL);
127+
}
128+
129+
void timing_start(void)
130+
{
131+
z_arm_dwt_cycle_count_start();
132+
}
133+
134+
void timing_stop(void)
135+
{
136+
DWT->CTRL &= ~DWT_CTRL_CYCCNTENA_Msk;
137+
}
138+
139+
timing_t timing_counter_get(void)
140+
{
141+
return (timing_t)z_arm_dwt_get_cycles();
142+
}
143+
144+
uint64_t timing_cycles_get(volatile timing_t *const start,
145+
volatile timing_t *const end)
146+
{
147+
return (*end - *start);
148+
}
149+
150+
uint64_t timing_freq_get(void)
151+
{
152+
return z_arm_dwt_freq_get();
153+
}
154+
155+
uint64_t timing_cycles_to_ns(uint64_t cycles)
156+
{
157+
return (cycles) * (NSEC_PER_USEC) / timing_freq_get_mhz();
158+
}
159+
160+
uint64_t timing_cycles_to_ns_avg(uint64_t cycles, uint32_t count)
161+
{
162+
return timing_cycles_to_ns(cycles) / count;
163+
}
164+
165+
uint32_t timing_freq_get_mhz(void)
166+
{
167+
return (uint32_t)(timing_freq_get() / 1000000);
168+
}

soc/arm/nordic_nrf/Kconfig.defconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,10 @@ config SYS_POWER_MANAGEMENT
3333
config BUILD_OUTPUT_HEX
3434
default y
3535

36+
if !CORTEX_M_DWT
3637
config SOC_HAS_TIMING_FUNCTIONS
3738
default y
39+
endif
3840

3941
config GPIO
4042
default y

0 commit comments

Comments
 (0)