Using DWT Peripheral to Write Delay Functions in STM32

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;
        }
    }
}

Leave a Comment