stm32F103C8T6标准库DWT基础应用1

目录

  • 1.DWT介绍
  • [2. DWT精度](#2. DWT精度)
  • [3.DWT 精确延时功能](#3.DWT 精确延时功能)
  • [4. DWT相关寄存器](#4. DWT相关寄存器)
    • [4.1 DEMCR](#4.1 DEMCR)
    • [4.2 DWT_CYCCNT](#4.2 DWT_CYCCNT)
    • [4.3 CYCCNTENA](#4.3 CYCCNTENA)
    • [4.4 寄存器总结](#4.4 寄存器总结)
  • [5. DWT宏定义编写](#5. DWT宏定义编写)
  • [6. DWT模块代码](#6. DWT模块代码)
    • [6.1 DWT初始化](#6.1 DWT初始化)
    • [6.2 获取当前时间戳](#6.2 获取当前时间戳)
    • [6.3 节拍数转换成对应的时间](#6.3 节拍数转换成对应的时间)
    • [6.4 us延时](#6.4 us延时)
    • [6.5 ms延时](#6.5 ms延时)
    • [6.6 s延时](#6.6 s延时)

1.DWT介绍

在Cortex-M里面有一个外设叫DWT(DataWatchpoint andTrace),是用于系统调试及跟踪,它有一个32位的寄存器叫CYCCNT,它是一个向上的计数器,记录的是内核时钟运行的个数,内核时钟跳动一次,该计数器就加1,精度非常高,决定内核的频率是多少。

2. DWT精度

例如本教程是基于F103系列,内核时钟是72M,那精度就是1/72M=14ns,而程序的运行时间都是微秒级别的,所以14ns的精度是远远够的。

假设内核频率为72M,内核跳一次的时间大概为1/72M=14ns(最长能记录的时间为:

60s=2的32次方/72000000)。

如果是H7这种400M主频的芯片,那它的计时精度高达1/400M=2.5ns。

如果是i.MXRT1052这种高速的处理器,假设内核频率为528M,内核跳一次的时间

大概为1/528M=1.9ns,(最长能记录的时间为:8.13s=2的32次方/528000000)。

当CYCCNT溢出之后,会清0重新开始向上计数。

3.DWT 精确延时功能

要实现延时的功能,总共涉及到三个寄存器:DEMCR、DWT_CTRL、DWT_CYCCNT,分别用于开启DWT功能、开启CYCCNT及获得系统时钟计数值。

详细内容出自文献《DDI0337Hcortexm3_r2p0_trm》与《CM3权威指南CnR2》等

4. DWT相关寄存器

4.1 DEMCR

想要使能DWT外设,需要由另外的内核调试寄存器DEMCR的位24控制,写1使能。

DEMCR的地址是:OxEOOOEDFC。关于该寄存器的详情见图DEMCR的位24写1使能。

4.2 DWT_CYCCNT

使能DWT_CYCCNT寄存器之前,先清0。其基地址是OxE0001004,复位默认值是0,

可读写类型。所以往0xE0001004这个地址写0,就将DWT_CYCCNT清0了。

4.3 CYCCNTENA

它是DWT控制寄存器(DWT_CTRL)的第一位,其基地址为:OxE0001000,写1使能,则启用CYCCNT计数器,否则CYCCNT计数器将不会工作。

4.4 寄存器总结

想要使用DWT的时候需要将 DEMCR寄存器的第24位写1使能。

想要查看计数的值,去看DWT_CYCCNT寄存器里面计数的值。

如果想要开始计数,DWT 控制寄存器 DWT_CTRL 的第 0 位 CYCCNTENA 置 1,开启 CYCCNT 硬件自增计数。

5. DWT宏定义编写

c 复制代码
/*DWT时间戳相关寄存器定义*/

#define DEMCR                   (*(uint32_t *)(0xE000EDFC))
#define DWT_CTRL                (*(uint32_t *)(0xE0001000))
#define DWT_CYCCNT              (*(uint32_t *)(0xE0001004))

#define DEMCR_TRCENA            (1 << 24)
#define DWT_CTRL_CYCCNTENA      (1 << 0)

外设叫DWT(Data Watchpoint and Trace,数据观察点与跟踪单元),该外设有一个32位的寄存器叫CYCCNT,

它是一个向上的计数器,记录的是内核时钟运行的个数,

内核每一个时钟周期时间大概为1/72M=14ns(最长能记录的时间约为:60s = 2的32次方 /72000000),

当CYCCNT溢出之后,自动清零,重新开始向上计数。

复制代码
开关1
DEMCR:调试异常与监控控制寄存器 (寄存器地址:0xE000EDFC)
    DEMCR_TRCENA:管理第24位使能(DWT工作)

开关2
DWT_CTRL:控制寄存器 (寄存器地址:0xE0001000)
    DWT_CTRL_CYCCNTENA:管理第0位(计数器工作)

DWT_CYCCNT:DWT 周期计数器寄存器 (寄存器地址:0xE0001004)
    存放计数值,CPU每一个时钟周期自动+1。(使用前需要软件手动清零)

使能CYCCNT计数的操作步骤:
1、先使能DWT外设准备,这个由内核调试寄存器DEMCR的位24控制,写1使能
2、使能CYCCNT计数器之前,先清0。
3、使能CYCCNT计数器,这个由DWT_CTRL的位0控制,写1使能

6. DWT模块代码

6.1 DWT初始化

c 复制代码
 /**
  * @brief  初始化 DWT 计数器 
  * @param  无
  * @retval 使用DWT延时函数之前,必须调用本函数
  */
void DWT_Init(void) 
{
    /* 1.先使能DWT设备准备 */
    DEMCR |= (uint32_t)DEMCR_TRCENA;
    
    /* 2.DWT CYCCNT寄存器清0 */
    DWT_CYCCNT = (uint32_t)0U;  //使能CYCCNT计数器之前,先清0。
    
    /* 使能Cortex-M DWT CYCCNT 寄存器 */
    DWT_CTRL |= (uint32_t)DWT_CTRL_CYCCNTENA;
}

6.2 获取当前时间戳

c 复制代码
 /**
  * @brief  获取当前的时间戳
  * @param  无
  * @retval 当前时间戳,即DWT_CYCCNT寄存器的值     
  */
uint32_t DWT_GetTick(void) 
{
    return (uint32_t)DWT_CYCCNT;
}

6.3 节拍数转换成对应的时间

c 复制代码
 /**
  * @brief  节拍数转化时间间隔(微秒单位)
  * @param  tick: 需要转换的节拍数
  * @param  frequency: 内核时钟频率
  * @retval 当前时间戳,即DWT_CYCCNT寄存器的值
  */
uint32_t DWT_TickToMicrosecond(uint32_t tick, uint32_t frequency) 
{
    return (uint32_t)1000000.0 / frequency * tick;
}

传入的tick=3600,代表需要累计走过 3600 个 CPU 内核时钟节拍 。

DWT‑CYCCNT 寄存器每个内核时钟周期自动 + 1;当DWT->CYCCNT − start这个差值累加到 3600 时,硬件层面真实流逝时间就是 50μs(CPU 主频 72MHz 条件下)。

这里的tick = `DWT->CYCCNT − start周期差值,只是用户只需要传递节拍数

CYCCNT和us互相转换:

1/SystemCoreClock*CYCCNT(s) = 1000/SystemCoreClock*CYCCNT(ms)

= 1000 000/SystemCoreClock*CYCCNT(us)= (x)us

6.4 us延时

c 复制代码
/**
  * @brief  DWT计数实现精确延时,32位计数器
  * @param  time : 延迟长度,单位1 us
  * @retval 无
  * @note   无
  */
void DWT_DelayUs(__IO uint32_t time)
{
    /* 将微秒转化为对应的时钟计数值*/
    uint32_t tick_duration= time * (SystemCoreClock / 1000000) ;
    uint32_t tick_start = DWT_GetTick();         /* 刚进入时的计数器值 */
    
    while(DWT_GetTick() - tick_start < tick_duration);
}

tick_duration= time * (SystemCoreClock / 1000000) ;

  • time:输入,单位 微秒 us
  • SystemCoreClock:内核时钟,单位 Hz
  • tick_duration:输出,DWT 需要的节拍数(就是DWT->CYCCNT‑start要达到的差值)

完整流程(72MHz,time=50)

  1. time=50,计算:tick_duration = 50 * (SystemCoreClock/1000000) → tick_duration = 3600
  2. tick_start = DWT->CYCCNT;,假设此刻寄存器读到 12400,tick_start =12400
  3. while 判断:(DWT->CYCCNT - tick_start) < 3600
    • 差值不到 3600:循环继续等待,CYCCNT 硬件持续 + 1
    • 差值 ≥3600:退出 while,延时完成

6.5 ms延时

c 复制代码
/**
  * @brief  DWT计数实现精确延时,32位计数器
  * @param  time : 延迟长度,单位1 ms
  * @retval 无
  */
void DWT_DelayMs(__IO uint32_t time)
{
    for(uint32_t i = 0; i < time; i++)
    {
        DWT_DelayUs(1000);
    }
}

6.6 s延时

c 复制代码
/**
  * @brief  DWT计数实现精确延时,32位计数器
  * @param  time : 延迟长度,单位1 s
  * @retval 无
  */
void DWT_DelayS(__IO uint32_t time)
{
    for(uint32_t i = 0; i < time; i++)
    {
        DWT_DelayMs(1000);
    }
}
相关推荐
碧海银沙音频科技研究院2 小时前
炬芯ATS3089X手表的HFP通话不自动路由到设备BT的问题解决
网络·人工智能·嵌入式硬件·算法
youcans_7 小时前
【STM32C5教程】(3)GPIO 按键输入实验
stm32·单片机·嵌入式硬件
俊基科技8 小时前
回音消不掉、底噪压不住、主板还对不上口?——A-59P 多功能语音处理模组技术解析
嵌入式硬件·回音消除·ai降噪模块
北京盛世宏博9 小时前
通信异常深度排查:以太网温湿度设备 TCP 粘包、UDP 丢包根治方案
单片机·网络协议·tcp/ip·udp·以太网·传感器·温湿度
蓝天居士10 小时前
PY32F系列MCU在串口接收时跑飞的根因分析(2)
单片机·嵌入式硬件
wuyk55513 小时前
嵌入式驱动开发:量产级工程化实战(第9篇)——低功耗下的通信可靠性
c语言·驱动开发·stm32·单片机·嵌入式硬件
创界工坊工作室13 小时前
24-基于单片机的仓鼠养殖环境监控系统设计
stm32·单片机·嵌入式硬件·proteus
碧海银沙音频科技研究院13 小时前
基于炬芯ATS录音卡BLE控制协议
人工智能·嵌入式硬件·算法·语音识别
comyccccc14 小时前
PCB走线设计秘籍:从载流到3D预览全解析学习笔记
单片机·嵌入式硬件
俊基科技15 小时前
A-59 工业级 AI 语音处理模组:100 dB 消回音 + 神经网络降噪的工程实践
嵌入式硬件·神经网络·硬件开发·语音模块·回音消除·拾音降噪