Skip to main content
AP_040
Senior
August 29, 2019
Solved

STM32L462 delay in a microsecond(us)

  • August 29, 2019
  • 9 replies
  • 29362 views

HAL Library provide the HAL_Delay() for millisecond delay. I want to use micro second delay in STM32L4 so how I do it? Is it available in HAL library?

Best answer by AP_040

I am done.

Added this dwt files in my project and working fine.

#ifndef DWT_STM32_DELAY_H
#define DWT_STM32_DELAY_H
 
#ifdef __cplusplus
extern "C" {
#endif
 
 
#include "stm32f1xx_hal.h"
uint32_t DWT_Delay_Init(void);
 
 
 
/**
 * @brief This function provides a delay (in microseconds)
 * @param microseconds: delay in microseconds
 */
__STATIC_INLINE void DWT_Delay_us(volatile uint32_t microseconds)
{
 uint32_t clk_cycle_start = DWT->CYCCNT;
 
 /* Go to number of cycles for system */
 microseconds *= (HAL_RCC_GetHCLKFreq() / 1000000);
 
 /* Delay till end */
 while ((DWT->CYCCNT - clk_cycle_start) < microseconds);
}
 
 
#ifdef __cplusplus
}
#endif
 
#endif

9 replies

Tesla DeLorean
Guru
August 29, 2019

Use a free running TIM at 1 MHz or faster, and delta the TIM->CNT​ in a loop until you get the elapsed micro-seconds

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
AP_040
AP_040Author
Senior
August 29, 2019

Hello @Community member​  I found below example and implement in my MCU but it is not properly delay the system.

//******************************************************************************

volatile unsigned int *DWT_CYCCNT = (volatile unsigned int *)0xE0001004; //address of the register

volatile unsigned int *DWT_CONTROL = (volatile unsigned int *)0xE0001000; //address of the register

volatile unsigned int *SCB_DEMCR = (volatile unsigned int *)0xE000EDFC; //address of the register

//******************************************************************************

void EnableTiming(void)

{

*SCB_DEMCR = *SCB_DEMCR | 0x01000000;

*DWT_CYCCNT = 0; // reset the counter

*DWT_CONTROL = *DWT_CONTROL | 1 ; // enable the counter

}

//******************************************************************************

void HAL_Delay_us(uint32_t tick)

{

unsigned int start, current;

start = *DWT_CYCCNT;

do

{

current = *DWT_CYCCNT;

} while((current - start) < tick);

}

Is it register address is different for my MCU?

Can I do it this way without free running timer?

Tesla DeLorean
Guru
August 29, 2019

Yes, this will work on non CM0(+) parts. CM7 parts need an unlock sequence

It will have the granularity of the CPU clock.

1ms = SystemCoreClock / 1000

1us = SystemCoreClock / 1000000

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
AP_040
AP_040Author
Senior
August 29, 2019

@Community member​ 

So, I need to change "1us = SystemCoreClock / 1000000" this in HAL_InitTick(). Is it?

HAL_SYSTICK_Config(SystemCoreClock / (1000000U/ uwTickFreq))

instead of

HAL_SYSTICK_Config(SystemCoreClock / (1000U / uwTickFreq))

This way?

Tesla DeLorean
Guru
August 29, 2019

No, this is simply a computation of CPU ticks passed into HAL_Delay_us() to achieve a milli-second, or micro-second of elapsed time. It doesn't use/change SysTick.

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
AP_040
AP_040AuthorBest answer
Senior
August 29, 2019

I am done.

Added this dwt files in my project and working fine.

#ifndef DWT_STM32_DELAY_H
#define DWT_STM32_DELAY_H
 
#ifdef __cplusplus
extern "C" {
#endif
 
 
#include "stm32f1xx_hal.h"
uint32_t DWT_Delay_Init(void);
 
 
 
/**
 * @brief This function provides a delay (in microseconds)
 * @param microseconds: delay in microseconds
 */
__STATIC_INLINE void DWT_Delay_us(volatile uint32_t microseconds)
{
 uint32_t clk_cycle_start = DWT->CYCCNT;
 
 /* Go to number of cycles for system */
 microseconds *= (HAL_RCC_GetHCLKFreq() / 1000000);
 
 /* Delay till end */
 while ((DWT->CYCCNT - clk_cycle_start) < microseconds);
}
 
 
#ifdef __cplusplus
}
#endif
 
#endif

S.Ma
Principal
August 29, 2019

You can simply do a nop loop if you know the core frequency. Otherwise, the lptimer is a good way to generate delays and callbacks.

AP_040
AP_040Author
Senior
August 30, 2019

@S.Ma​  Yes, we can do it using LPtimer and callbacks but still I have note worked with timer yet. So, can you please help me how I generate microseconds delay using timer itself?

S.Ma
Principal
August 30, 2019

This forum is inadequate to share source code (did answer and shared this kind of source code already), I'm not going to do the extra mile to compensate for the forum missing services. One there is an STM32 community Git repo for code example, snippets, projets with web links to use on this forum, it may make things much more efficient sharing know-how.

Piranha
Principal III
August 31, 2019

> You can simply do a nop loop

No, You can't.

https://developer.arm.com/docs/dui0553/a/the-cortex-m4-instruction-set/miscellaneous-instructions/nop

NOP does nothing. NOP is not necessarily a time-consuming NOP. The processor might remove it from the pipeline before it reaches the execution stage.

Use NOP for padding, for example to place the following instruction on a 64-bit boundary.

Tesla DeLorean
Guru
August 31, 2019

Also it doesn't account for time in interrupts

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
HDaji.1
Senior
May 9, 2024

I tried the DWT method in my code. It basically works.

However, I have 2 issues:

  1. The delay time is not so accurate; and does not go linear with input value.
  2. I wonder if it's OK to call DWT_Delay_Init(void) multiple times.