DWT is a debugging peripheral, and one of its core functions is CYCCNT, which is a 32-bit incrementing counter used to record the number of clock cycles executed by the CPU. We can achieve rewriting the HAL_Delay function or implement microsecond-level delays by monitoring the changes in this counter.
Appendix:
1. Source Code
- dwt.delay.h file
#ifndef __DWT_DELAY_H
#define __DWT_DELAY_H
#include "stm32g4xx.h"
/* Get the core clock frequency */
#define GET_CPU_ClkFreq() HAL_RCC_GetSysClockFreq()
uint32_t CPU_TS_TmrRd(void);
HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority);
// Maximum delay value is 8 seconds
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 file
#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 Initialize timestamp function, called during initialization
* @param None
* @retval None
*/
HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
{
/* Enable DWT peripheral */
DEM_CR |= (uint32_t)DEM_CR_TRCENA;
/* Clear DWT CYCCNT register count to 0 */
DWT_CYCCNT = (uint32_t)0u;
/* Enable Cortex-M DWT CYCCNT register */
DWT_CR |= (uint32_t)DWT_CR_CYCCNTENA;
return HAL_OK;
}
/**
* @brief Read the current timestamp, updated every 1ms
* @param None
* @retval ms timestamp
*/
uint32_t HAL_GetTick(void)
{
return ((uint32_t)DWT_CYCCNT / GET_CPU_ClkFreq() * 1000);
}
/**
* @brief Implement precise delay using the CPU's internal counter, 32-bit counter, maximum delay time 8 seconds
* @param us : Delay length, unit 1 us
* @retval None
*/
void dwt_delay_us(uint32_t us)
{
uint32_t ticks;
uint32_t told, tnow, tcnt=0;
ticks = us * (GET_CPU_ClkFreq() / 1000000); /* Required number of ticks */
tcnt = 0;
told = (uint32_t)DWT_CYCCNT; /* Counter value when just entered */
while(1)
{
tnow = (uint32_t)DWT_CYCCNT;
if(tnow != told)
{
if(tnow > told)
{
tcnt += tnow - told;
}
else /* Reload */
{
tcnt += UINT32_MAX - told + tnow;
}
told = tnow;
/* Exit if the time exceeds or equals the delay time */
if(tcnt >= ticks) break;
}
}
}