Fundamentals 7 min read

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.

Liangxu Linux
Liangxu Linux
Liangxu Linux
How to Enable and Use Cortex‑M DWT CYCCNT for Precise Cycle Counting

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 bit

3.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 CYCCNT

Reference: 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
}
DWT diagram
DWT diagram
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

DebuggingembeddedCortex-MCYCCNTcycle countingDWT
Liangxu Linux
Written by

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.)

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.