1、DWT
1.1、DWT简介
DWT(Data watchpoint and trace unit)数据观察点与跟踪单元。它是内核调试组件的一部分,它提供的调试功能包括:
1. 它包含了 4 个比较器,可以配置成在发生比较匹配时,执行如下动作:
a) 硬件观察点(产生一个观察点调试事件,并且用它来调用调试模式,包括停机模式和调试监视器模式
b) ETM 触发,可以触发 ETM 发出一个数据包,并汇入指令跟踪数据流中
c) 程序计数器(PC)采样器事件触发
d) 数据地址采样器触发
e) 第一个比较器还能用于比较时钟周期计数器(CYCCNT),用于取代对数据地址的比较
2. 作为计数器, DWT 可以对下列项目进行计数:
a) 时钟周期(CYCCNT)
b) 被折叠(Folded) 的指令
c) 对加载/存储单元(LSU)的操作
d) 睡眠的时钟周期
e) 每指令周期数(CPI)
f) 中断的额外开销(overhead)
3. 以固定的周期采样 PC 的值
4. 中断事件跟踪
当用于硬件观察点或 ETM 触发时,比较器既可以比较数据地址,也可以比较程序计数器 PC。
当用于其它功能时,比较器则只能比较数据地址。
1.2、寄存器简介

每一个比较器都有 3 个寄存器
- COMP 寄存器
- MASK 寄存器
- FUNCTION 控制寄存器
其中, COMP 寄存器是一个 32 位寄存器,用于存储要比较的值。 MASK 寄存器可以用于掩蔽数据地址的一些位,被掩蔽的位不参与比较。FUNCTION寄存器用于决定比较器的功能。
2、DWT的几种用法介绍
#define __I volatile const /*! Defines 'read only' structure member permissions */
#define __O volatile /*! Defines 'write only' structure member permissions */
#define __IO volatile /*! Defines 'read / write' structure member permissions */
typedef struct
{
__IO uint32_t CTRL; /*!< Offset: 0x000 (R/W) Control Register */
__IO uint32_t CYCCNT; /*!< Offset: 0x004 (R/W) Cycle Count Register */
__IO uint32_t CPICNT; /*!< Offset: 0x008 (R/W) CPI Count Register */
__IO uint32_t EXCCNT; /*!< Offset: 0x00C (R/W) Exception Overhead Count Register */
__IO uint32_t SLEEPCNT; /*!< Offset: 0x010 (R/W) Sleep Count Register */
__IO uint32_t LSUCNT; /*!< Offset: 0x014 (R/W) LSU Count Register */
__IO uint32_t FOLDCNT; /*!< Offset: 0x018 (R/W) Folded-instruction Count Register */
__I uint32_t PCSR; /*!< Offset: 0x01C (R/ ) Program Counter Sample Register */
__IO uint32_t COMP0; /*!< Offset: 0x020 (R/W) Comparator Register 0 */
__IO uint32_t MASK0; /*!< Offset: 0x024 (R/W) Mask Register 0 */
__IO uint32_t FUNCTION0; /*!< Offset: 0x028 (R/W) Function Register 0 */
uint32_t RESERVED0[1U];
__IO uint32_t COMP1; /*!< Offset: 0x030 (R/W) Comparator Register 1 */
__IO uint32_t MASK1; /*!< Offset: 0x034 (R/W) Mask Register 1 */
__IO uint32_t FUNCTION1; /*!< Offset: 0x038 (R/W) Function Register 1 */
uint32_t RESERVED1[1U];
__IO uint32_t COMP2; /*!< Offset: 0x040 (R/W) Comparator Register 2 */
__IO uint32_t MASK2; /*!< Offset: 0x044 (R/W) Mask Register 2 */
__IO uint32_t FUNCTION2; /*!< Offset: 0x048 (R/W) Function Register 2 */
uint32_t RESERVED2[1U];
__IO uint32_t COMP3; /*!< Offset: 0x050 (R/W) Comparator Register 3 */
__IO uint32_t MASK3; /*!< Offset: 0x054 (R/W) Mask Register 3 */
__IO uint32_t FUNCTION3; /*!< Offset: 0x058 (R/W) Function Register 3 */
} DWT_Type;
typedef struct
{
__IO uint32_t DHCSR; /*!< Offset: 0x000 (R/W) Debug Halting Control and Status Register */
__O uint32_t DCRSR; /*!< Offset: 0x004 ( /W) Debug Core Register Selector Register */
__IO uint32_t DCRDR; /*!< Offset: 0x008 (R/W) Debug Core Register Data Register */
__IO uint32_t DEMCR; /*!< Offset: 0x00C (R/W) Debug Exception and Monitor Control Register */
} CoreDebug_Type;
#define DWT_BASE (0xE0001000UL) /*!< DWT Base Address */
#define CoreDebug_BASE (0xE000EDF0UL) /*!< Core Debug Base Address */
#define DWT ((DWT_Type *) DWT_BASE ) /*!< DWT configuration struct */
#define CoreDebug ((CoreDebug_Type *) CoreDebug_BASE) /*!< Core Debug configuration struct */
#define CoreDebug_DEMCR_TRCENA_Msk (1UL << 24U) /*!< CoreDebug DEMCR: TRCENA Mask */
#define CoreDebug_DEMCR_MON_EN_Msk (1UL << 16U) /*!< CoreDebug DEMCR: MON_EN Mask */
#define DWT_CTRL_CYCCNTENA_Msk (1UL << 0U) /*!< DWT CTRL: CYCCNTENA Mask */
#define DWT_FUNCTION_MATCHED_Msk (1UL << 24U) /*!< DWT FUNCTION: MATCHED Mask */
#define DWT_FUNCTION_DATAVSIZE_Pos 10U /*!< DWT FUNCTION: DATAVSIZE Position */
#define DWT_FUNCTION_DATAVMATCH_Pos 8U /*!< DWT FUNCTION: DATAVMATCH Position */
#define DWT_FUNCTION_CYCMATCH_Pos 7U /*!< DWT FUNCTION: CYCMATCH Position */
#define DWT_FUNCTION_MATCH_Pos 0U /*!< DWT FUNCTION: MATCH Position */
#define CPU_FREQ_MHZ 150 /*!< CPU Frequence in MHz */
2.1、高精度延时
现象:在主循环中以1Hz的频率闪烁led灯
void dwt_tim_init(void)
{
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk | CoreDebug_DEMCR_MON_EN_Msk; //Enable DWT function
DWT->CYCCNT = 0; //Clear Count register
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; //Enable CYCCNT
}
void dwt_delay_us(uint32_t us)
{
uint32_t tick;
tick = us * CPU_FREQ_MHZ;
DWT->CYCCNT = 0;
while (DWT->CYCCNT < tick);
}
void dwt_delay_ms(uint32_t ms)
{
dwt_delay_us(ms*1000);
}
void main(void)
{
dwt_tim_init();
while (1)
{
dwt_delay_ms(500);
toggle_led();
}
}
2.2、高精度定时器
现象:在DebugMon中断中以1Hz的频率闪烁led灯
注意:只有COMP0寄存器能与CYCCNT寄存器做比较产生中断
void dwt_tim_init(void)
{
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk | CoreDebug_DEMCR_MON_EN_Msk; //Enable DWT function
DWT->CYCCNT = 0; //Clear Count register
DWT->COMP0 = CPU_FREQ_MHZ * 1000 * 1000; //Tick is 1S
DWT->MASK0 = 0;
DWT->FUNCTION0 = (2UL << DWT_FUNCTION_DATAVSIZE_Pos) | //For data value matching is word
(1UL << DWT_FUNCTION_DATAVMATCH_Pos) | //Perform data value comparison
(1UL << DWT_FUNCTION_CYCMATCH_Pos) | //Compare with the cycle counter
(6UL << DWT_FUNCTION_MATCH_Pos); //Generate watchpoint debug event
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; //Enable CYCCNT
}
void DebugMon_Handler(void)
{
if (DWT->FUNCTION0 & DWT_FUNCTION_MATCHED_Msk){
DWT->CYCCNT = 0; //clear count register
toggle_led();
}
}
void main(void)
{
__NVIC_SetPriority(DebugMonitor_IRQn, 0);
dwt_tim_init();
while (1)
{
task_scheduling();
}
}
2.3、函数运行时间统计
void dwt_tim_init(void)
{
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk | CoreDebug_DEMCR_MON_EN_Msk; //Enable DWT function
}
void dwt_tim_start(void)
{
DWT->CYCCNT = 0; //Clear Count register
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; //Enable CYCCNT
}
uint32_t dwt_tim_stop(void)
{
DWT->CTRL &= ~DWT_CTRL_CYCCNTENA_Msk; //Disable CYCCNT
return DWT->CYCCNT;
}
void main(void)
{
uint32_t tick, time_us;
dwt_tim_init();
while (1)
{
dwt_tim_start();
task1_run();
tick = dwt_tim_stop();
time_us = tick * ( 1 / CPU_FREQ_MHZ)
task2_run();
}
}
2.4、寄存器修改监控
现象:主循环中每秒对地址0x4003A000进行写入操作,触发DebugMon中断,使led灯以1Hz的频率闪烁。
注意:由于DWT只有4个COMP寄存器,因此最多只能同时监控4个地址。
void dwt_monitor_init(void)
{
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk | CoreDebug_DEMCR_MON_EN_Msk; //Enable DWT function
DWT->COMP0 = 0x4003A000; //You want to monitor address
DWT->MASK0 = 0;
DWT->FUNCTION0 = (2UL << DWT_FUNCTION_DATAVSIZE_Pos) | //For data value matching is word
(6UL << DWT_FUNCTION_MATCH_Pos); //Generate watchpoint debug event
}
void DebugMon_Handler(void)
{
if (DWT->FUNCTION0 & DWT_FUNCTION_MATCHED_Msk){
toggle_led();
}
}
void main(void)
{
__NVIC_SetPriority(DebugMonitor_IRQn, 0);
dwt_monitor_init();
while (1)
{
delay_ms(1000);
*((uint32_t*)0x4003A000) |= 0x1;
}
}
3、注意事项
DWT的相关寄存器在debug时,会被JLink修改,因此上述用法均需在非debug模式下使用。
4、参考资料
[1]【STM32】基于DWT的延时功能实现_stm32 dwt-优快云博客
[2] ARM Cortex-M3与Cortex-M4权威指南
[3] ARMv7-M Architecture Reference Manual
2217

被折叠的 条评论
为什么被折叠?



