在 STM32 性能调试、代码执行时间测量场景中,DWT(Data Watchpoint and Trace) 内置的 CYCCNT 周期计数器是最高效的工具 —— 它以内核主频为时钟,32 位无干扰计数,精度可达单周期级别,比 SysTick 更适合精准测时。但不少使用 STM32H7(Cortex‑M7,Arm v7‑M 架构)的开发者会遇到:上电 / 复位后 DWT 无法启动计数的问题。
本文基于 ST 官方 LAT1209 应用笔记,一次性讲清 DWT 启用的核心寄存器约束、标准配置步骤与可直接移植的代码,解决复位后无法计数的痛点。
资料获取:【应用笔记】LAT1209 Arm®v7-M架构的STM32如何启用DWT进行计数
1. DWT 无法启用的根本原因
Arm v7‑M 架构(Cortex‑M3/M4/M7)中,DWT 模块的全局时钟由DEMCR(Debug Exception and Monitor Control Register) 统一控制:
- 上电复位后,DEMCR 所有位默认为0;
- 第 24 位TRCENA为 0 时,DWT 与 ITM 模块全局禁用,即便配置 CYCCNT 也不会计数。
这就是复位后 DWT 不工作的直接原因。而在 Cortex‑M7 内核(如 STM32H7/F7)中,还多一层写保护:必须先向DWT_LAR写入解锁密钥0xC5ACCE55,才能修改 DWT 控制寄存器,否则配置不生效。
2. DWT 周期计数启用标准步骤
基于 CMSIS 标准头文件,仅需 4 步即可稳定启用 DWT CYCCNT 计数器,适配所有 Arm v7‑M 架构 STM32:
- 使能 DEMCR.TRCENA,打开 DWT 全局时钟;
- Cortex‑M7 内核解锁 DWT 写保护;
- 清零 CYCCNT 计数器,保证起始计数干净;
- 使能 DWT_CTRL.CYCCNTENA,启动周期计数。
3. 可直接移植的实操代码
代码基于 CMSIS 标准宏定义,无需手动操作地址,包含core_cm7.h(Cortex‑M7)或对应内核头文件即可编译运行。
#include "core_cm7.h" // 根据内核选择:cm3.h/cm4.h/cm7.h
void DWT_Init(void)
{
// 1. 全局使能DWT + ITM模块
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
// 2. Cortex-M7 解锁DWT写保护(关键!M3/M4可省略)
DWT->LAR = 0xC5ACCE55;
// 3. 清零周期计数器
DWT->CYCCNT = 0;
// 4. 使能CYCCNT计数
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
}
测量代码执行周期示例
// 初始化DWT
DWT_Init();
// 记录起始周期
uint32_t start_cycles = DWT->CYCCNT;
/* 需要测量的业务代码 */
// HAL_Delay(1);
// 计算消耗周期数
uint32_t used_cycles = DWT->CYCCNT - start_cycles;
4. 关键寄存器与注意事项
- DEMCR.TRCENA(bit24):全局开关,任何 v7‑M 架构 MCU 都必须先置 1,DWT 才能工作。
- DWT_LAR 解锁:仅 Cortex‑M7(H7/F7)需要,固定密钥
0xC5ACCE55,写入后才可配置 DWT 寄存器。 - CYCCNT 特性:32 位向上计数器,溢出自动归零,时钟频率 = 内核主频,无中断、无 CPU 占用。
- 适用内核:本方法兼容所有 Arm v7‑M 架构:Cortex‑M3、Cortex‑M4、Cortex‑M7。
Arm v7‑M 架构 STM32 启用 DWT 计数,只要抓住两点就能彻底解决复位不工作问题:
- 先置位 DEMCR 的 TRCENA 位,打开 DWT 全局时钟;
- Cortex‑M7 内核必须先解锁 DWT_LAR,再配置计数器。
按照本文标准代码初始化后,DWT CYCCNT 即可在上电 / 复位后稳定工作,精准测量代码执行周期、评估算法性能、定位时序问题,是嵌入式调试的必备基础能力。
1211