0
0
Power-electronicsHow-ToBeginner · 3 min read

How to Create Microsecond Delay in Embedded C

To create a microsecond delay in embedded C, use hardware timers configured to count microseconds or implement a calibrated busy-wait loop with known clock cycles. Using timer registers is the most accurate method, while a for loop delay depends on processor speed and compiler optimization.
📐

Syntax

Microsecond delay can be created by configuring a hardware timer or by writing a busy-wait loop. The typical syntax for a busy-wait loop is:

void delay_us(unsigned int microseconds) {
    while(microseconds--) {
        // calibrated nop or empty loop
    }
}

For hardware timers, you set timer registers to count the required microseconds and wait for the timer flag.

c
void delay_us(unsigned int microseconds) {
    while(microseconds--) {
        // calibrated nop or empty loop
    }
}
💻

Example

This example shows a simple busy-wait loop delay function assuming a 16 MHz CPU clock. The loop is calibrated to approximately 1 microsecond per iteration.

c
#include <stdint.h>

void delay_us(uint32_t us) {
    // Approximate delay for 1 microsecond at 16 MHz
    volatile uint32_t count;
    while(us--) {
        count = 16; // Adjust this value for your CPU speed
        while(count--) {
            __asm__("nop"); // Prevent optimization
        }
    }
}

int main() {
    // Example usage: delay 10 microseconds
    delay_us(10);
    return 0;
}
⚠️

Common Pitfalls

  • Uncalibrated loops: Busy-wait loops vary with CPU speed and compiler optimization, causing inaccurate delays.
  • Interrupts: Interrupts can extend delay time unexpectedly if not disabled.
  • Timer configuration: Incorrect timer prescaler or count values lead to wrong delay durations.

Always calibrate delay loops for your specific hardware and consider using hardware timers for precise timing.

c
/* Wrong way: uncalibrated loop, may be optimized away */
void delay_us_wrong(unsigned int us) {
    while(us--) {
        for(int i=0; i<100; i++) {
            // empty loop
        }
    }
}

/* Right way: use volatile and nop to prevent optimization */
void delay_us_right(unsigned int us) {
    volatile int i;
    while(us--) {
        for(i=0; i<16; i++) {
            __asm__("nop");
        }
    }
}
📊

Quick Reference

MethodDescriptionAccuracyNotes
Busy-wait loopSimple CPU cycle counting loopLow to mediumNeeds calibration, affected by compiler and CPU speed
Hardware timerUse MCU timer registersHighMost accurate, requires timer setup
Delay functions from librariesPrebuilt delay APIsDepends on implementationEasy but check underlying method
Disabling interruptsPrevent delay interruptionImproves accuracyMay affect system responsiveness

Key Takeaways

Use hardware timers for the most accurate microsecond delays in embedded C.
Busy-wait loops require careful calibration and can be affected by compiler optimizations.
Disable interrupts during delay if precise timing is critical.
Always test delay functions on your target hardware to ensure accuracy.
Avoid empty loops without volatile or nop instructions to prevent compiler removal.