DWT 是一个调试外设,它的核心功能之一是 CYCCNT (Cycle Count),这是一个32位递增计数器,用于记录 CPU 执行的时钟周期数量。我们可以通过对这个计数器的变化来实现高精度延时。
在使用 DWT 延时之前,需要完成以下操作:
- 使能 DWT
- 使能 CYCCNT
- 清零 CYCCNT
- 基于 CYCCNT 实现延时逻辑
源码如下:
- dwt.delay.h文件
C
#ifndef __DWT_DELAY_H
#define __DWT_DELAY_H
#include "stm32g4xx.h"
/* 获取内核时钟频率 */
#define GET_CPU_ClkFreq() HAL_RCC_GetSysClockFreq()
uint32_t CPU_TS_TmrRd(void);
HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority);
//最大延时值为8秒
void dwt_delay_us(uint32_t us);
#define HAL_Delay(ms) dwt_delay_us(ms*1000)
#define dwt_delay_s(s) dwt_delay_us(s*1000000)
#endif /* __DWT_DELAY_H */
- dwt_delay.c文件
C
#include "dwt_delay.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)
/**
* @brief 初始化时间戳
* @param 无
* @retval 无
* @note 使用延时函数前,必须调用本函数
*/
HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
{
/* 使能DWT外设 */
DEM_CR |= (uint32_t)DEM_CR_TRCENA;
/* DWT CYCCNT寄存器计数清0 */
DWT_CYCCNT = (uint32_t)0u;
/* 使能Cortex-M DWT CYCCNT寄存器 */
DWT_CR |= (uint32_t)DWT_CR_CYCCNTENA;
return HAL_OK;
}
/**
* @brief 读取当前时间戳,每1ms更新一次
* @param 无
* @retval ms时间戳
*/
uint32_t HAL_GetTick(void)
{
return ((uint32_t)DWT_CYCCNT/(GET_CPU_ClkFreq()*1000));
}
/**
* @brief 采用CPU的内部计数实现精确延时,32位计数器,最大延时时间8秒
* @param us : 延迟长度,单位1 us
* @retval 无
*/
void dwt_delay_us(uint32_t us)
{
uint32_t ticks;
uint32_t told,tnow,tcnt=0;
ticks = us * (GET_CPU_ClkFreq() / 1000000); /* 需要的节拍数 */
tcnt = 0;
told = (uint32_t)DWT_CYCCNT; /* 刚进入时的计数器值 */
while(1)
{
tnow = (uint32_t)DWT_CYCCNT;
if(tnow != told)
{
if(tnow > told)
{
tcnt += tnow - told;
}
else /* 重新装载 */
{
tcnt += UINT32_MAX - told + tnow;
}
told = tnow;
/*时间超过/等于要延迟的时间,则退出 */
if(tcnt >= ticks)break;
}
}
}