|
|
@@ -3,6 +3,7 @@
|
|
|
#include <atomic>
|
|
|
|
|
|
#include <freertos/FreeRTOS.h>
|
|
|
+#include <freertos/semphr.h>
|
|
|
#include <freertos/task.h>
|
|
|
|
|
|
#include "esphome/core/component.h"
|
|
|
@@ -136,6 +137,7 @@ class GxEPD2Display : public display::DisplayBuffer {
|
|
|
// shared spi: bus should mostly be fine - but that's about the
|
|
|
// write phase, not this task boundary, and hasn't been stress-tested
|
|
|
// against another device on the same bus mid-refresh.
|
|
|
+ this->lambda_done_sem_ = xSemaphoreCreateBinary();
|
|
|
xTaskCreate(&GxEPD2Display::update_task_trampoline_, "gxepd2_update", 4096, this, 1, &this->update_task_);
|
|
|
}
|
|
|
|
|
|
@@ -146,6 +148,14 @@ class GxEPD2Display : public display::DisplayBuffer {
|
|
|
return;
|
|
|
}
|
|
|
xTaskNotifyGive(this->update_task_);
|
|
|
+ // Block only through this frame's draw lambda - not through the SPI
|
|
|
+ // write / physical refresh that follows, which continues on
|
|
|
+ // update_task_ after we return. For a paged (height_divisor > 1) model
|
|
|
+ // this only covers the first page: the lambda runs again per
|
|
|
+ // subsequent page, interleaved with that page's hardware write, fully
|
|
|
+ // in the background. Most models are single-page, where this is the
|
|
|
+ // entire draw phase.
|
|
|
+ xSemaphoreTake(this->lambda_done_sem_, portMAX_DELAY);
|
|
|
}
|
|
|
|
|
|
void dump_config() override {
|
|
|
@@ -206,8 +216,17 @@ class GxEPD2Display : public display::DisplayBuffer {
|
|
|
uint32_t start = millis();
|
|
|
this->driver_->setFullWindow();
|
|
|
this->driver_->firstPage();
|
|
|
+ bool first_page = true;
|
|
|
do {
|
|
|
this->do_update_();
|
|
|
+ if (first_page) {
|
|
|
+ // update() is waiting on exactly this: the draw lambda for the
|
|
|
+ // first (often only) page has finished, so the caller can
|
|
|
+ // proceed while the SPI write and physical refresh below run
|
|
|
+ // without it.
|
|
|
+ xSemaphoreGive(this->lambda_done_sem_);
|
|
|
+ first_page = false;
|
|
|
+ }
|
|
|
} while (this->driver_->nextPage());
|
|
|
ESP_LOGD(TAG, "Display update took %u ms", (unsigned) (millis() - start));
|
|
|
this->update_running_.store(false, std::memory_order_release);
|
|
|
@@ -215,6 +234,7 @@ class GxEPD2Display : public display::DisplayBuffer {
|
|
|
}
|
|
|
|
|
|
TaskHandle_t update_task_{nullptr};
|
|
|
+ SemaphoreHandle_t lambda_done_sem_{nullptr};
|
|
|
std::atomic<bool> update_running_{false};
|
|
|
};
|
|
|
|