Microsecond (µs) Delay Implementation for STM32H743 Using SysTick

ampheoampheo
4 min read

Here's a complete, optimized implementation for the STM32H743 (Cortex-M7) with 480MHz clock capability, including advanced techniques for maximum precision.

1. SysTick Configuration for STM32H743

Basic Polling Implementation

c

#include "stm32h7xx.h"

// Initialize SysTick for µs delays (no interrupt)
void SysTick_Init(void) {
    // STM32H743 runs at up to 480MHz, but check your actual clock
    uint32_t clock = SystemCoreClock; 

    // Configure for 1µs ticks (adjust if clock not multiple of 1MHz)
    SysTick->LOAD = (clock / 1000000) - 1;
    SysTick->VAL = 0;
    SysTick->CTRL = SysTick_CTRL_ENABLE_Msk | 
                   SysTick_CTRL_CLKSOURCE_Msk; // Use processor clock
}

// Blocking delay in microseconds
void delay_us(uint32_t us) {
    SysTick->VAL = 0;  // Reset counter
    while (us--) {
        while (!(SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk));
    }
}

Key Points for STM32H743

  • Clock Warning: The H7 can run up to 480MHz. Verify your actual clock with:

    c

      printf("System clock: %lu Hz\n", SystemCoreClock);
    
  • Division Handling: If SystemCoreClock isn't a multiple of 1MHz (e.g., 400MHz), use:

    c

      SysTick->LOAD = (SystemCoreClock / 1000000) - 1; // Truncates remainder
    

2. Advanced: DWT Cycle Counter (Nanosecond Precision)

The STM32H743's Data Watchpoint and Trace (DWT) unit provides cycle-accurate timing.

DWT Implementation

c

#define DEMCR           (*((volatile uint32_t *)0xE000EDFC))
#define DWT_CTRL        (*((volatile uint32_t *)0xE0001000))
#define DWT_CYCCNT      (*((volatile uint32_t *)0xE0001004))

void DWT_Init(void) {
    DEMCR |= 1 << 24;       // Enable DWT
    DWT_CYCCNT = 0;         // Reset counter
    DWT_CTRL |= 1 << 0;     // Enable cycle counting
}

// Delay in microseconds using CPU cycles
void delay_us(uint32_t us) {
    uint32_t start = DWT_CYCCNT;
    uint32_t cycles = us * (SystemCoreClock / 1000000);
    while ((DWT_CYCCNT - start) < cycles);
}

Advantages

  • Sub-µs precision: At 480MHz, 1 cycle = 2.08ns.

  • No timer configuration: Uses built-in debug hardware.


3. Hybrid Approach (SysTick + DWT)

Combine both methods for flexibility:

c

void delay_us(uint32_t us) {
    // Use DWT if available (more precise)
    if (DWT_CTRL & 1) {
        uint32_t start = DWT_CYCCNT;
        uint32_t cycles = us * (SystemCoreClock / 1000000);
        while ((DWT_CYCCNT - start) < cycles);
    }
    // Fallback to SysTick
    else {
        SysTick->VAL = 0;
        while (us--) {
            while (!(SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk));
        }
    }
}

4. STM32H743-Specific Optimizations

Cache Considerations

The H7 has L1 cache. For consistent timing:

c

SCB_EnableICache();  // Enable instruction cache
SCB_EnableDCache();  // Enable data cache (if needed)

Clock Tree Verification

Confirm your clock settings in SystemClock_Config():

c

RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 5;     // Input divider
RCC_OscInitStruct.PLL.PLLN = 192;   // VCO multiplier
RCC_OscInitStruct.PLL.PLLP = 2;     // System clock divider
RCC_OscInitStruct.PLL.PLLQ = 4;     // For peripherals
HAL_RCC_OscConfig(&RCC_OscInitStruct);

5. Testing & Validation

Oscilloscope Test

  1. Toggle a GPIO pin before/after delay:

    c

     HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
     delay_us(10);  // Should show 10µs pulse
     HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
    
  2. Measure pulse width to verify accuracy.

Serial Debug Output

c

uint32_t start = DWT_CYCCNT;
delay_us(100);
uint32_t elapsed = DWT_CYCCNT - start;
printf("Actual delay: %lu cycles (%lu us)\n", 
       elapsed, elapsed / (SystemCoreClock / 1000000));

6. Performance Comparison

MethodPrecisionCPU OverheadMax Delay
SysTick Polling±1µs100%~89ms @480MHz
DWT Counter±2.08ns0%Unlimited
TIM Hardware±10ns0%Unlimited

7. Troubleshooting STM32H743

IssueSolution
No delay occursCheck SystemCoreClock value and clock tree configuration.
Delay too long/shortVerify PLL settings in SystemClock_Config().
DWT not workingEnsure DEMCR bit 24 is set before enabling DWT.
Inconsistent timingDisable interrupts or use __disable_irq() during critical delays.

  1. For general use: SysTick polling (simple and reliable).

  2. For extreme precision: DWT cycle counter.

  3. For long delays (>100ms): Combine with HAL's HAL_Delay().

c

// Example: 100µs delay with DWT fallback to SysTick
void delay_us(uint32_t us) {
    if (DWT_CTRL & 1) {  // DWT available
        uint32_t start = DWT_CYCCNT;
        uint32_t cycles = us * (SystemCoreClock / 1000000);
        while ((DWT_CYCCNT - start) < cycles);
    } else {             // SysTick fallback
        SysTick->VAL = 0;
        while (us--) {
            while (!(SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk));
        }
    }
}
0
Subscribe to my newsletter

Read articles from ampheo directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

ampheo
ampheo