Tuesday, June 11, 2019

How to create 1 microsecond delay in STM32

HAL_Delay is able to provide minimum 1ms delay but when it comes to microsecond, there isn’t any predefined function to create 1us delay. In this tutorial, I am going to show you how to create 1 microsecond delay in STM32. The process will be same for all the STM32 devices, you need to make a minor change though.

WHY Delay in MicroSeconds

Delay in microseconds is needed in order to interface some sensors for eg- DHT11/22. These sensors contains only one PIN for the data transfer and data is transferred bidirectionally. They need precise timing in order to work. For eg- To initialize DHT22, microcontroller need to pull the data pin low for 500us and than pull high for 40us. After that DHT22 start transmitting it’s response by pulling the line low for 80us followed by pulling high for 80us.
After searching a lot on the internet, finally I got the code which works. I don’t remember where I got it from so if someone knows the writer, do let me know in the comments below. I will give the credits for the work.
I will show the working on the oscilloscope, You can check the  RESULTS tab for more details. I am using STM32F103C8 cortex M3 microcontroller but the process is same for other STM32 devices.

How to setup

This project contains a header file (dwt_stm32_delay.h) and a c file (dwt_stm32_delay.c). We need to include it in the main project. I am using keil and the process is described below:
First setup the project from the CubeMx and right click the Application/Userand select add existing files to group
add both files in the project
As you can see above that the folder is included in the path
Next you have to include dwt_stm32_delay.h in the main file by using #include “dwt_stm32_delay.h” and build the project. Now you will be able to see the *.h and *.c file in the list.
NOTE:-  Inside dwt_stm32_delay.h, change the #include”*.h” file according to your microcontroller.
You can use DWT_Delay_Init (); to initialize the delay and DWT_Delay_us (microseconds) for the delay in us.

#include <stdint.h>
#ifndef INC_DWT_DELAY_H_
#define INC_DWT_DELAY_H_
#define DWT_DELAY_NEWBIE 0
void DWT_Init(void);
void DWT_Delay(uint32_t us);
#endif /* INC_DWT_DELAY_DWT_DELAY_H_ */



#include "stm32f1xx_hal.h"          // change to whatever MCU you use
#include "dwt_delay.h"

/**
 * Initialization routine.
 * You might need to enable access to DWT registers on Cortex-M7
 *   DWT->LAR = 0xC5ACCE55
 */
void DWT_Init(void)
{
    if (!(CoreDebug->DEMCR & CoreDebug_DEMCR_TRCENA_Msk)) {
        CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
        DWT->CYCCNT = 0;
        DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
    }
}

#if DWT_DELAY_NEWBIE
/**
 * If you are a newbie and see magic in DWT_Delay, consider this more
 * illustrative function, where you explicitly determine a counter
 * value when delay should stop while keeping things in bounds of uint32.
*/
void DWT_Delay(uint32_t us) // microseconds
{
    uint32_t startTick  = DWT->CYCCNT,
             targetTick = DWT->CYCCNT + us * (SystemCoreClock/1000000);

    // Must check if target tick is out of bounds and overflowed
    if (targetTick > startTick) {
        // Not overflowed
        while (DWT->CYCCNT < targetTick);
    } else {
        // Overflowed
        while (DWT->CYCCNT > startTick || DWT->CYCCNT < targetTick);
    }
}
#else
/**
 * Delay routine itself.
 * Time is in microseconds (1/1000000th of a second), not to be
 * confused with millisecond (1/1000th).
 *
 * No need to check an overflow. Let it just tick :)
 *
 * @param uint32_t us  Number of microseconds to delay for
 */
void DWT_Delay(uint32_t us) // microseconds
{
    uint32_t startTick = DWT->CYCCNT,
             delayTicks = us * (SystemCoreClock/1000000);

    while (DWT->CYCCNT - startTick < delayTicks);
}

#endif

No comments:

Post a Comment

Back to Top