1. Topic

The differences between vTaskDelay(), vTaskDelayUntil(), esp_timer, GPTimer, RMT and MCPWM/LEDC on ESP32, and TIM/Input Capture/Output Compare/DMA on STM32. Main idea: vTaskDelay() is not a precise physical timer.

2. Why this matters in a project

Accurate timing is needed for phase timestamps, sync/PPS/20 Hz, IR illumination, HIL, watchdog heartbeats and measuring input -> event -> transport latency.

3. Theory

Four levels of timing:

text
1. FreeRTOS delay: vTaskDelay/vTaskDelayUntil, ms-level periodic tasks.
2. Software timer: esp_timer, timestamp/timeouts.
3. Hardware timer: GPTimer/TIM, precise interrupts/counters.
4. Specialized peripheral: RMT/MCPWM/LEDC/TIM PWM/Input Capture/Output Compare/DMA.

vTaskDelay() means that a task does not run for the requested N ticks. It runs again when the scheduler gives it CPU time. This can be suitable for polling inputs every 1-5 ms, but not for a precise 200 us pulse. For periodic tasks, prefer:

c
TickType_t last = xTaskGetTickCount();
while (1) {
    do_input_poll();
    vTaskDelayUntil(&last, pdMS_TO_TICKS(2));
}

An ESP32 timestamp:

c
int64_t now_us = esp_timer_get_time();

Hardware timing:

  • Input Capture latches the timer counter in hardware at an edge.
  • Output Compare generates an event when counter == CCR.
  • PWM + DMA can update CCR/duty without involving the CPU at each edge.
  • RMT is useful for accurately timed pulse sequences.

4. Common mistakes

  1. Generating a precise pulse with vTaskDelay().
  2. Performing I2C/MQTT/logging in a timer callback or ISR.
  3. Adding the timestamp after expensive processing.
  4. Sharing one timer between PWM, profiling, capture and scheduling without a policy.
  5. Capturing noisy AC input without a Schmitt trigger/comparator.
  6. Ignoring timer counter overflow.

5. Practical task

Create TIMING_POLICY.md:

markdown
# Timing policy
| Need | ESP32 tool | STM32 tool |
|---|---|---|
| Periodic task | vTaskDelayUntil | osDelayUntil |
| Timestamp | esp_timer_get_time | TIM counter |
| Precise interrupt | GPTimer | TIM update IRQ |
| PWM | LEDC/MCPWM/RMT | TIM PWM |
| Input timestamp | GPIO ISR/RMT/GPTimer | TIM input capture |
| Output event | GPTimer/MCPWM/RMT | TIM output compare |

Add raw_sample_us, detected_us, confirmed_us, queued_us and sent_us to phase_event_t.

6. Further reading and experiments

ESP-IDF esp_timer, GPTimer and LEDC/MCPWM/RMT; STM32 HAL TIM; ST AN4013; experiments with input capture and output compare.

A timer callback detects an event. Where should MQTT/I2C processing run?

Exercise

Choose a mechanism for housekeeping every 100 ms, a physical 200 us pulse, and timing an external edge. Explain what vTaskDelayUntil() does not guarantee.

Self-check criteria: Name a mechanism for every role, distinguish capture from ISR timestamping, and state the scheduler limitation.

Show the supplied answer

Housekeeping: vTaskDelayUntil or an appropriate software timer. Pulse: a hardware timer/specialized peripheral. Edge: hardware Input Capture where supported, or a GPIO ISR with evaluated latency. vTaskDelayUntil maintains a tick-based period but does not remove scheduler/interrupt latency or make a task a physical timer.