Cortex-M系列单片机DWT组件的几种用法

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值