// helper macros for creating unique variable names #define CONCAT_IMPL(x, y) x##y #define CONCAT(x, y) CONCAT_IMPL(x, y) #define delay_us(us) delay_us_INTERNAL(__COUNTER__, us) // forward declaration so the macro can reference the class class delayMicrosec; // this macro instantiates a static delayMicrosec() object per call site // identified by __COUNTER__ so each use of delay_us() has its own timer #define delay_us_INTERNAL(n, us) \ static delayMicrosec CONCAT(delay_us_, n); \ CONCAT(delay_us_, n).wait(us) // non-blocking delayMicroseconds() class delayMicrosec { private: esp_timer_handle_t timer; TaskHandle_t task; public: delayMicrosec() : timer(nullptr), task(nullptr) {} void wait(uint32_t us) { task = xTaskGetCurrentTaskHandle(); if (!timer) { esp_timer_create_args_t args = { .callback = [](void* arg) { delayMicrosec* self = static_cast(arg); BaseType_t xHigherPriorityTaskWoken = pdFALSE; vTaskNotifyGiveFromISR(self->task, &xHigherPriorityTaskWoken); if (xHigherPriorityTaskWoken) { portYIELD_FROM_ISR(); } }, .arg = this, .dispatch_method = ESP_TIMER_TASK, .name = "delay_us_timer" }; esp_timer_create(&args, &timer); } esp_timer_start_once(timer, us); ulTaskNotifyTake(pdTRUE, portMAX_DELAY); } };