Microsecond/Nanoseconds delay in STM32
HAL_Delay
is able to provide minimum 1 ms delay, but when it comes to microseconds, there isn’t any predefined function to create 1 us delay in HAL Library. In this tutorial, we will see how to create microsecond delays in STM32. We will be using one of the Timer to do so. The process will be same for all the STM32 devices, you need to make some minor changes though.
I am using STM32F103C8 controller with CubeIDE, but as I mentioned it will work same for other microcontrollers with any other IDE also.
CubeMX Configuration
This is the most important part of this process, so read this section very carefully. First of all we need to decide which Timer to use for the process. There is no special requirement, just choose any one. I will use timer 1.
As you can see in the image below (from the datasheet), the TIM1 is connected to the APB2 clock. This is a very important piece of information, and you should know it about the timer that you are going to use.
Now, let’s start the cubeIDE, and open the clock setup tab. Here you can see once I set the HCLK at MAX i.e. 72MHz, the APB2 clock is also at 72MHz.
This means that the TIMER 1 is also running at 72MHz, as the TIM1 is connected to the APB2. Now, let’s reduce this frequency in the timer setup section.
- First set the clock source to internal clock.
- Prescaler divides the Timer clock further, by the value that you input in the prescaler.
- As we want the delay of 1 microsecond, the timer frequency must be (1/(1 us)), i.e 1 MHz. And for this reason, the prescaler value is 72.
- Note that it’s 72-1, because the prescaler will add 1 to any value that you input there.
- The ARR I am setting is the max value it can have. I have set it to 0xFFFF-1 (MAX for a 16 bit Register).
Basically, the counter is going to count from 0 to ARR. Every count will take 1 us. So setting this value as high as possible is the best, because this way you can have large delays also.
I have also enabled the pin PA1 as output, so that we can see the result in an oscilloscope.
Some insight into the CODE
Now, we will write a function to create this 1 us delay. Below is the one.
void delay_us (uint16_t us)
{
__HAL_TIM_SET_COUNTER(&htim1,0); // set the counter value a 0
while (__HAL_TIM_GET_COUNTER(&htim1) < us); // wait for the counter to reach the us input in the parameter
}
When the function is called with the parameter as the number of microseconds, the following operations takes place
- The TIM1 counter will reset to 0.
- The counter will start counting up, till the value (us) has been reached.
- Once the value is reached, the function will exit.
As I mentioned before, each count takes 1 us, and therefore the counter will keep counting in microseconds until the input value has reached. Once it happens, the control will come out of the loop, and we have had achieved the delay.
Inside the main loop, we must start the timer, after all the peripherals are initialised.
int main ()
{
....
HAL_TIM_Base_Start(&htim1);
while (1)
{
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_1);
delay_us(10);
}
}
To use the required delay, all we have to do is use the function that we created above.
Result