5 Techniques to Delay Code Execution

An interesting problem that often comes up in embedded software implementation is figuring out how to delay code execution. Sometimes a developer might just want there to be a 10-microsecond delay to allow an I/O line to stabilize before reading it or may want a specified time period between reads to debounce it. In this post, we will explore five techniques for delaying code execution.

 

Technique #1 – A conditional loop

The first technique, which is probably the most used and simplest is to use a conditional loop. A conditional loop delay will often use a for, while or do while loop to execute a no operation (NOP) instruction repeatedly. For example:

for(int i = 0; i < 100000; i++)
{
   __NOP();
}

A conditional delay can be useful in a pinch but it’s hardly accurate or effective. If a developer were to adjust the clock frequency for a different operational mode such as low power operation, the delay time will be completely different. Plus, there is always a question about how much of a delay is that really? One might think it’s 100,000 instructions but each time through the loop there will be additional instructions to check the loop variables and increment i. These timing loops are just too unpredictable for use in any production code.

 

Technique #2 – Use a timer

A second technique that can be used is to leverage a hardware timer built into the microcontroller. There are often several different hardware timers that can be used to keep track of system time, generate waveforms, capture inputs and general purpose. If a developer needs a delay such as 10 microseconds, a hardware timer could be loaded with the count value that would represent 10 microseconds. In this instance, the timer would be setup as a one-shot timer. The code would start the timer and wait for the timer overflow flag to be set which would then indicate that the time has elapsed.

An abstracted version of this code could look something like the following:

Timer_Reload(DELAY_VALUE);

while(Timer_Expired() == false)
{
   __NOP();
}

This technique is much more robust than the conditional loop we looked at earlier. It’s also more portable and can be more easily tuned for the desired delay period. In fact, the API can be reused through-out the code to allow a single timer to be used for any number of delays that are required.

 

Technique #3 – Use a system tick (HAL Example)

There may be instances where a dedicated hardware timer is not available or setting up a one-shot timer is undesirable. In these circumstances, developers can leverage an onboard system tick to create the delay. Even bare-metal systems usually have a background timer that acts as a system tick so that the software has a time reference from the moment the microcontroller has started. Usually these system ticks are set to occur every 1 or 10 milliseconds in a typical system.

The system usually employs some API that allows a developer to access the current system tick such as SysTick_Get(). Developers can leverage this to create a delay similar to the following:

TimeStart = SysTick_Get();

do
{
   TimeNow = SysTick_Get();
   TimeDelta = TimeNow – TimeStart;
}while(TimeDelta < DelayTime);


Developers just need to make sure that if they do something like this that they will not run into wrap around calculation issues or other potential issues so the boundary conditions should be checked.

 

Technique #4 – Use RTOS yield function

In a more advanced system that is using a real-time operating system (RTOS), developers can leverage built in RTOS API calls for yielding a task to create a delay. For example, if a developer were using FreeRTOS, within their task they could use code like the following:

VTaskDelay(1);

 

This delay function will cause the task to yield the current task for one RTOS tick. The RTOS tick may be set to one millisecond or ten depending on the configuration. There may be a problem with using a delay mechanism like this because the task will yield the CPU for that period but there is no guarantee that the task will be the highest priority task once the system tick period has expired! The task will only run immediately after the delay if the task is the highest priority task that is ready to run so there could be some jitter to the delay time.

 

Technique #5 – Use RTOS objects

The last technique that we will discuss today is the use of other RTOS objects to delay time. If you carefully look at the API’s for objects such as semaphores, mutexes and queues within your favorite RTOS, you’ll notice that most API calls that wait will also include a delay time. This delay time can be used to cause a delay in the application as well.

Related to the RTOS objects is that most RTOS’s also include soft timers. These are software-based timers that are triggered from a running hardware timer. Techniques similar to those shown in technique #2 and technique #3 can then be used with those soft timers to create a delay in the code execution.

 

Conclusions

As we have seen in today’s post, there are several different techniques that are available to developers who want to delay their codes execution. The technique that is used will depend on the software and hardware resources available in the system. Developers can then decide how sophisticated a solution they want to use. At the end of the day though, there are certainly several mechanisms that can help to delay code execution by a defined time period.

Share >