How to Enable and Use Cortex‑M DWT CYCCNT for Precise Cycle Counting
This guide explains the DWT tracing component in Cortex‑M processors, details the CYCCNT register’s precision and limits, and provides step‑by‑step instructions with register definitions and multiple code examples for enabling, resetting, starting, stopping, and reading the cycle counter.
1. DWT Tracking Component
The Data Watchpoint and Trace (DWT) unit provides data observation points and tracing capabilities. It is commonly used for profiling by counting events, especially via the 32‑bit CYCCNT register, which increments on each core clock cycle and can serve as a high‑resolution time base for measuring task execution time or CPU usage.
2. DWT in Cortex‑M
Cortex‑M processors include a DWT peripheral. The CYCCNT register increments on every core clock tick; with a 72 MHz clock the resolution is 14 ns, sufficient for microsecond‑level measurements. The 32‑bit counter overflows after 2³²‑1 counts, i.e., about 59.65 seconds (2³² / 72 000 000). After overflow the counter wraps to zero.
3. Usage Method
Three registers are involved:
DEMCR – Debug Exception and Monitor Control Register (enables DWT when bit 24 is set).
DWT_CTRL – DWT Control Register (enables CYCCNT via bit 0, CYCCNTENA).
DWT_CYCCNT – Cycle Count Register (holds the current cycle count).
3.1 DEMCR
// 0xE000EDFC DEMCR – Debug Exception and Monitor Control Register
#define DEMCR (*(unsigned int *)0xE000EDFC)
#define TRCENA (1U << 24) // DWT enable bit3.2 DWT_CYCCNT
// 0xE0001004 DWT_CYCCNT – Cycle Count Register
#define DWT_CYCCNT (*(unsigned int *)0xE0001004)3.3 CYCCNTENA
// 0xE0001000 DWT_CTRL – DWT Control Register
#define DWT_CTRL (*(unsigned int *)0xE0001000)
#define CYCCNTENA (1U << 0) // Enable CYCCNTReference: https://developer.arm.com/documentation/ddi0337/e/system-debug/dwt/summary-and-description-of-the-dwt-registers?lang=en
4. Summary of Steps
Enable the DWT peripheral by setting DEMCR bit 24.
Clear the CYCCNT register to zero.
Enable CYCCNT by setting DWT_CTRL bit 0 ( CYCCNTENA).
Register Definitions
// 0xE000EDFC DEMCR
#define DEMCR (*(unsigned int *)0xE000EDFC)
#define TRCENA (1U << 24)
// 0xE0001000 DWT_CTRL
#define DWT_CTRL (*(unsigned int *)0xE0001000)
#define CYCCNTENA (1U << 0)
// 0xE0001004 DWT_CYCCNT
#define DWT_CYCCNT (*(unsigned int *)0xE0001004)Usage Example
volatile unsigned int *DWT_CYCCNT;
volatile unsigned int *DWT_CTRL;
volatile unsigned int *SCB_DEMCR;
void reset_timer(void) {
DWT_CYCCNT = (unsigned int *)0xE0001004; // CYCCNT address
DWT_CTRL = (unsigned int *)0xE0001000; // DWT_CTRL address
SCB_DEMCR = (unsigned int *)0xE000EDFC; // DEMCR address
*SCB_DEMCR |= 0x01000000; // enable DWT (TRCENA)
*DWT_CYCCNT = 0; // clear counter
*DWT_CTRL = 0; // ensure disabled
}
void start_timer(void) {
*DWT_CTRL |= 1; // enable CYCCNT
}
void stop_timer(void) {
*DWT_CTRL &= ~1; // disable CYCCNT
}
unsigned int getCycles(void) {
return *DWT_CYCCNT;
}
void main(void) {
// ... your code ...
reset_timer();
start_timer();
// code to profile
myFunction();
stop_timer();
unsigned int cycles = getCycles();
// use cycles value
}Alternative Macro‑Based Example
#define start_timer() *((volatile uint32_t*)0xE0001000) = 0x40000001 // enable CYCCNT
#define stop_timer() *((volatile uint32_t*)0xE0001000) = 0x40000000 // disable CYCCNT
#define get_timer() *((volatile uint32_t*)0xE0001004) // read CYCCNT
/* Usage */
uint32_t start = get_timer();
start_timer();
// ... code ...
uint32_t end = get_timer();
stop_timer();
uint32_t cycles = end - start;Full Macro Example for Initialization
#define DWT_CR *(uint32_t *)0xE0001000
#define DWT_CYCCNT *(uint32_t *)0xE0001004
#define DEM_CR *(uint32_t *)0xE000EDFC
#define DEM_CR_TRCENA (1U << 24)
#define DWT_CR_CYCCNTENA (1U << 0)
void CPU_TS_TmrInit(void) {
DEM_CR |= DEM_CR_TRCENA; // enable DWT peripheral
DWT_CYCCNT = 0U; // clear counter
DWT_CR |= DWT_CR_CYCCNTENA; // enable CYCCNT
}
uint32_t OS_TS_GET(void) {
return DWT_CYCCNT; // read current cycle count
}Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Liangxu Linux
Liangxu, a self‑taught IT professional now working as a Linux development engineer at a Fortune 500 multinational, shares extensive Linux knowledge—fundamentals, applications, tools, plus Git, databases, Raspberry Pi, etc. (Reply “Linux” to receive essential resources.)
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
