之前的文章讲到过Systick定时器,其实DWT内核定时器也是很常见的,而且就是基本上arm内核的芯片都会有这个芯片,这就给我们进行移植提供了方便,关于Systick定时器的记录可以查看:Systick定时器使用以及一些问题记录
1、内核定时器介绍
在 Cortex-M 里面有一个外设叫 DWT(Data Watchpoint and Trace),是用于系统调试及跟踪, 它有一个 32 位的寄存器叫 CYCCNT,它是一个向上的计数器,记录的是内核时钟运行的个数,内核时钟跳动一次,该计数器就加 1。
从上面我们知道就是内核定时器和内核时钟有关,以 F103 系列为例,内核时钟是 72M,那精度就是 1/72M = 14ns,而程序的运行时间都是微秒级别的,所以 14ns 的精度是远远够的。最长能记录的时间为: 60s=2 的 32 次方/72000000(假设内核频率为 72M,内核跳一次的时间大概为 1/72M=14ns),而如果是 H7这种 400M 主频的芯片,那它的计时精度高达 2.5ns( 1/400000000 = 2.5)。当计数器溢出之后,会清 0 重新开始向上计数。
DWT定时器的时钟框图如下所示(图中红色框框出)
使用的寄存器说明:
- 1、DEMCR 内核调试寄存器:该寄存器的24位可以决定是否使能内核定时器,写1使能
- 2、DWT_CYCCNT 使能 DWT_CYCCNT 寄存器之前,先清 0。 其基地址是 0xE0001004, 复位默认值是 0,为可读写类型。所以往 0xE0001004 这个地址写就将 DWT_CYCCNT 清 0 了
- 3、CYCCNTENA 它是 DWT 控制寄存器的第一位,写 1 使能,则启用 CYCCNT 计数器,否则 CYCCNT计数器将不会工作。
2、使用内核定时器
首先定义下寄存器的地址:
下面就可以开始设置计数函数了:
适当修改增加ms还有s的计数函数:
之后就可以在主函数中进行调用了!
3、源码
DWT_time.c
/*
* DWT_time.c
*
* Created on: Mar 13, 2022
* Author: LX
*/
#include "DWT_time.h"
void vDWTDelayInit(void)
{
DEM_CR |= DEM_CR_TRCENA;
DWT_CYCCNT = 0;
DWT_CR |= DWT_CR_CYCCNTENA;
}
void vDWTDelayUs(float fTime)
{
volatile uint32_t uiTimeStop = 0u, uiTimeStart = 0;
if(fTime < 0.1f)
return;
uiTimeStart = DWT_CYCCNT;
uiTimeStop = (uint32_t)((SystemCoreClock / 1000000u) * fTime) + uiTimeStart;
if(uiTimeStop >= uiTimeStart)
while((DWT_CYCCNT > uiTimeStart) && (DWT_CYCCNT < uiTimeStop));
else
while(!((DWT_CYCCNT > uiTimeStop) && (DWT_CYCCNT < uiTimeStart)));
}
void vDWTDelayMs(float fTime)
{
volatile uint32_t uiTimeStop = 0u, uiTimeStart = 0;
if(fTime < 0.01f)
return;
uiTimeStart = DWT_CYCCNT;
uiTimeStop = (uint32_t)((SystemCoreClock / 1000u) * fTime) + uiTimeStart;
if(uiTimeStop >= uiTimeStart)
while((DWT_CYCCNT > uiTimeStart) && (DWT_CYCCNT < uiTimeStop));
else
while(!((DWT_CYCCNT > uiTimeStop) && (DWT_CYCCNT < uiTimeStart)));
}
void vDWTDelayS(uint32_t uiTime)
{
uint32_t i = 0u;
if(uiTime < 1u)
return;
for(i = 0u; i < uiTime; ++i)
{
vDWTDelayMs(1000);
}
}
DWT_time.h
/*
* DWY_time.h
*
* Created on: Mar 13, 2022
* Author: LX
*/
#ifndef DWT_TIME_H_
#define DWT_TIME_H_
#include "main.h"
#define DWT_CR *(__IO uint32_t *)0xE0001000
#define DWT_CYCCNT *(__IO uint32_t *)0xE0001004
#define DEM_CR *(__IO uint32_t *)0xE000EDFC
#define DEM_CR_TRCENA (1 << 24)
#define DWT_CR_CYCCNTENA (1 << 0)
void vDWTDelayInit(void);
void vDWTDelayS(uint32_t uiTime);
void vDWTDelayMs(float fTime);
void vDWTDelayUs(float fTime);
#endif /* DWT_TIME_H_ */