From 65023ca120cd270f5d77734b92cb85493f47d9c2 Mon Sep 17 00:00:00 2001 From: Mateusz Grzywacz Date: Wed, 20 Jan 2021 13:46:13 +0100 Subject: [PATCH] [EGD-5256] Eink display - speed up in some scenarios Causes slight speed-up in specific scenarios (changing windows, also: then rapid navigation) also: on a regular basis (shaky temperature measumt.) --- module-bsp/board/linux/eink/ED028TC1.c | 2 +- module-bsp/board/linux/eink/ED028TC1.h | 6 +- module-bsp/board/rt1051/bsp/eink/ED028TC1.cpp | 25 +-- module-bsp/board/rt1051/bsp/eink/ED028TC1.h | 6 +- module-bsp/board/rt1051/bsp/eink/bsp_eink.h | 2 +- module-services/service-eink/CMakeLists.txt | 2 +- module-services/service-eink/EinkDisplay.cpp | 149 ++++++++++++------ module-services/service-eink/EinkDisplay.hpp | 14 +- module-services/service-eink/ServiceEink.cpp | 22 +-- module-services/service-eink/ServiceEink.hpp | 2 +- .../messages/PrepareDisplayEarlyRequest.cpp | 15 ++ ...est.hpp => PrepareDisplayEarlyRequest.hpp} | 4 +- .../messages/PrepareDisplayRequest.cpp | 15 -- module-services/service-gui/ServiceGUI.cpp | 28 ++-- module-services/service-gui/ServiceGUI.hpp | 4 +- .../{EinkReady.hpp => EinkInitialized.hpp} | 4 +- 16 files changed, 178 insertions(+), 122 deletions(-) create mode 100644 module-services/service-eink/messages/PrepareDisplayEarlyRequest.cpp rename module-services/service-eink/messages/{PrepareDisplayRequest.hpp => PrepareDisplayEarlyRequest.hpp} (75%) delete mode 100644 module-services/service-eink/messages/PrepareDisplayRequest.cpp rename module-services/service-gui/messages/{EinkReady.hpp => EinkInitialized.hpp} (78%) diff --git a/module-bsp/board/linux/eink/ED028TC1.c b/module-bsp/board/linux/eink/ED028TC1.c index d9bd07c3b99ad8010b068a1b650cd559d4e83c11..4d7323bf024283929fcb807b160485a0cbdceee7 100644 --- a/module-bsp/board/linux/eink/ED028TC1.c +++ b/module-bsp/board/linux/eink/ED028TC1.c @@ -129,7 +129,7 @@ EinkStatus_e EinkResetAndInitialize() return EinkOK; } -EinkStatus_e EinkUpdateWaveform(const EinkWaveFormSettings_t *settings) +EinkStatus_e EinkUpdateWaveform(const EinkWaveformSettings_t *settings) { return EinkOK; } diff --git a/module-bsp/board/linux/eink/ED028TC1.h b/module-bsp/board/linux/eink/ED028TC1.h index 4748d11eebf7926259d265108833ec10b6340c1e..ac54129d468e4f649d60e777ce1b25ec0426355f 100644 --- a/module-bsp/board/linux/eink/ED028TC1.h +++ b/module-bsp/board/linux/eink/ED028TC1.h @@ -297,6 +297,8 @@ extern "C" EinkWaveforms_e mode; // temperature of surrounding int32_t temperature; + // use counter to keep track if need to change + uint32_t useCounter; // pointer to lookup table for lut c uint8_t *LUTCData; // sizeo of lutc data @@ -305,7 +307,7 @@ extern "C" uint8_t *LUTDData; // size of lutd data uint32_t LUTDSize; - } EinkWaveFormSettings_t; + } EinkWaveformSettings_t; /* Exported constants --------------------------------------------------------*/ @@ -419,7 +421,7 @@ extern "C" * @param LUTCData [in] - Data * @return */ - EinkStatus_e EinkUpdateWaveform(const EinkWaveFormSettings_t *settings); + EinkStatus_e EinkUpdateWaveform(const EinkWaveformSettings_t *settings); /** * This function converts the ARGB image to the L4 format diff --git a/module-bsp/board/rt1051/bsp/eink/ED028TC1.cpp b/module-bsp/board/rt1051/bsp/eink/ED028TC1.cpp index cf7ee4055fc34afc26d19260f15ce76426510ed6..317c63aebeb2e026d125168a5b8c2980621f5488 100644 --- a/module-bsp/board/rt1051/bsp/eink/ED028TC1.cpp +++ b/module-bsp/board/rt1051/bsp/eink/ED028TC1.cpp @@ -65,8 +65,6 @@ #define _delay_ms(ms) vTaskDelay(pdMS_TO_TICKS(ms)) -#define EINK_SUSPEND_TASK_TILL_EPD_BUSY() BSP_EinkWaitUntilDisplayBusy(pdMS_TO_TICKS(1000)) - //#define EINK_DEBUG_LOG 1 // //#if EINK_DEBUG_LOG == 1 @@ -81,14 +79,11 @@ using namespace magic_enum; static std::shared_ptr dma; static std::shared_ptr dmamux; -#define EINK_LUTS_FILE_PATH "/Luts.bin" - /* Internal variable definitions */ static uint8_t s_einkIsPoweredOn = false; // Variable which contains the state of the power of the EPD display static EinkWaveforms_e s_einkConfiguredWaveform = EinkWaveformGC16; // This variable contains the current waveform set in the display -static int8_t s_einkPreviousTemperature = 127; // This variable contains the last measured temperature of the ambient static CACHEABLE_SECTION_SDRAM(uint8_t s_einkServiceRotatedBuf[BOARD_EINK_DISPLAY_RES_X * BOARD_EINK_DISPLAY_RES_Y / 2 + 2]); // Plus 2 for the EPD command and BPP config @@ -548,7 +543,7 @@ void EinkPowerOn() return; } - EINK_SUSPEND_TASK_TILL_EPD_BUSY(); + BSP_EinkWaitUntilDisplayBusy(pdMS_TO_TICKS(BSP_EinkBusyTimeout)); s_einkIsPoweredOn = true; } } @@ -563,7 +558,7 @@ void EinkPowerOff() return; } - EINK_SUSPEND_TASK_TILL_EPD_BUSY(); + BSP_EinkWaitUntilDisplayBusy(pdMS_TO_TICKS(BSP_EinkBusyTimeout)); s_einkIsPoweredOn = false; } } @@ -590,7 +585,7 @@ int16_t EinkGetTemperatureInternal() return -1; } - EINK_SUSPEND_TASK_TILL_EPD_BUSY(); + BSP_EinkWaitUntilDisplayBusy(pdMS_TO_TICKS(BSP_EinkBusyTimeout)); if (BSP_EinkReadData(temp, sizeof(temp), SPI_MANUAL_CS) != 0) { // LOG_ERROR("Requesting the temperature FAILED"); @@ -641,8 +636,8 @@ static void s_EinkSetInitialConfig() } tmpbuf[0] = EinkPanelSetting; // 0x00 - tmpbuf[1] = LUT_SEL | SHL | RST_N; // 0x25 -> _XON _RES0 LUT_SEL _DM - SHL _SPIWM RST_N // If 0x35 (DM - 1 is used - // (2bpp)) the SPI speed can be 25MHz + tmpbuf[1] = LUT_SEL | SHL | RST_N; // 0x25 -> _XON _RES0 LUT_SEL _DM - SHL _SPIWM RST_N + // If 0x35 (DM - 1 is used (2bpp)) the SPI speed can be 25MHz tmpbuf[2] = 0x00; if (BSP_EinkWriteData(tmpbuf, 3, SPI_AUTOMATIC_CS) != 0) { // LOG_ERROR("Setting the initial configuration for the Eink failed"); @@ -747,13 +742,9 @@ EinkStatus_e EinkResetAndInitialize() return EinkOK; } -EinkStatus_e EinkUpdateWaveform(const EinkWaveFormSettings_t *settings) +EinkStatus_e EinkUpdateWaveform(const EinkWaveformSettings_t *settings) { - // If neither the temperature nor the waveform has changed - do nothing - if ((settings->temperature == s_einkPreviousTemperature) && (settings->mode == s_einkConfiguredWaveform)) { - return EinkOK; - } - + /// LUTD if (BSP_EinkWriteData(settings->LUTDData, settings->LUTDSize, SPI_AUTOMATIC_CS) != 0) { EinkResetAndInitialize(); return EinkSPIErr; @@ -1015,7 +1006,7 @@ EinkStatus_e EinkRefreshImage( return EinkSPIErr; } - EINK_SUSPEND_TASK_TILL_EPD_BUSY(); + BSP_EinkWaitUntilDisplayBusy(pdMS_TO_TICKS(BSP_EinkBusyTimeout)); return EinkOK; } diff --git a/module-bsp/board/rt1051/bsp/eink/ED028TC1.h b/module-bsp/board/rt1051/bsp/eink/ED028TC1.h index 2eafa36071909c9a13cbe5418fb24b5ab905918e..81f9d9448b8f0fa51fbd72bdcc9bf2c8f51ec983 100644 --- a/module-bsp/board/rt1051/bsp/eink/ED028TC1.h +++ b/module-bsp/board/rt1051/bsp/eink/ED028TC1.h @@ -297,6 +297,8 @@ extern "C" EinkWaveforms_e mode; // temperature of surrounding int32_t temperature; + // counts usage of this waveform (display refreshes) + uint32_t useCounter; // pointer to lookup table for lut c uint8_t *LUTCData; // sizeo of lutc data @@ -305,7 +307,7 @@ extern "C" uint8_t *LUTDData; // size of lutd data uint32_t LUTDSize; - } EinkWaveFormSettings_t; + } EinkWaveformSettings_t; /* Exported constants --------------------------------------------------------*/ @@ -419,7 +421,7 @@ extern "C" * @param LUTCData [in] - Data * @return */ - EinkStatus_e EinkUpdateWaveform(const EinkWaveFormSettings_t *settings); + EinkStatus_e EinkUpdateWaveform(const EinkWaveformSettings_t *settings); /** * This function converts the ARGB image to the L4 format diff --git a/module-bsp/board/rt1051/bsp/eink/bsp_eink.h b/module-bsp/board/rt1051/bsp/eink/bsp_eink.h index a42012db958b80b8a2d2b31b7f171c87fa3aa8a2..2f0a6deb0515f8a5efb74bd61cd8a2a70b85f0ad 100644 --- a/module-bsp/board/rt1051/bsp/eink/bsp_eink.h +++ b/module-bsp/board/rt1051/bsp/eink/bsp_eink.h @@ -33,7 +33,7 @@ extern "C" typedef void (*bsp_eink_BusyEvent)(void); -#define BSP_EINK_TRANSFER_TIMEOUT_MS 1000 + inline constexpr auto BSP_EinkBusyTimeout = 3000U; status_t BSP_EinkInit(bsp_eink_BusyEvent event); void BSP_EinkDeinit(void); diff --git a/module-services/service-eink/CMakeLists.txt b/module-services/service-eink/CMakeLists.txt index bcb71c169ed3cbb0986d2f4a5a6c145c68d70d0b..5a50cb03a9fd704c598103b50b29bfd0c673a743 100644 --- a/module-services/service-eink/CMakeLists.txt +++ b/module-services/service-eink/CMakeLists.txt @@ -16,7 +16,7 @@ set(SOURCES ServiceEink.cpp EinkDisplay.cpp messages/ImageMessage.cpp - messages/PrepareDisplayRequest.cpp + messages/PrepareDisplayEarlyRequest.cpp ) add_library(${PROJECT_NAME} STATIC ${SOURCES}) diff --git a/module-services/service-eink/EinkDisplay.cpp b/module-services/service-eink/EinkDisplay.cpp index fbcfc35d8bce96b1e716f8938e412797e2a48868..b6812757f8f6299a453fa0d195a5aa6e2023b648 100644 --- a/module-services/service-eink/EinkDisplay.cpp +++ b/module-services/service-eink/EinkDisplay.cpp @@ -17,17 +17,23 @@ namespace service::eink constexpr auto LutsFileName = "Luts.bin"; constexpr auto LUTDSize = 16385; constexpr auto LUTCSize = 64; - constexpr auto LUTRSize = 256; ///< Needed due to \ref EINK_LUTS_FILE_PATH structure + constexpr auto LUTRSize = 256; ///< Needed due to \ref LutsFileName structure constexpr auto LUTSTotalSize = LUTDSize + LUTCSize + LUTRSize; - constexpr auto LUTVersionInterval = 3; - constexpr auto LUTSubcritical = 12; - constexpr auto LUTCritical = 13; - EinkWaveFormSettings_t createDefaultWaveFormSettings(EinkWaveforms_e waveformMode) + constexpr auto LUTTemperatureMinimal = 0; + constexpr auto LUTTemperatureSubcritical = 38; + constexpr auto LUTTemperatureCritical = 43; + + constexpr auto LUTTemperatureOffsetInterval = 3; + constexpr auto LUTTemperatureOffsetSubcritical = 12; + constexpr auto LUTTemperatureOffsetCritical = 13; + + EinkWaveformSettings_t createDefaultWaveFormSettings(EinkWaveforms_e waveformMode) { - EinkWaveFormSettings_t settings{}; + EinkWaveformSettings_t settings{}; settings.mode = waveformMode; settings.temperature = DefaultSurroundingTemperature; + settings.useCounter = 0; settings.LUTCData = nullptr; settings.LUTCSize = 0; settings.LUTDData = nullptr; @@ -37,14 +43,14 @@ namespace service::eink } // namespace EinkDisplay::EinkDisplay(::gui::Size screenSize) - : size{screenSize}, waveformSettings{createDefaultWaveFormSettings(EinkWaveformGC16)}, + : size{screenSize}, currentWaveform{createDefaultWaveFormSettings(EinkWaveformGC16)}, displayMode{EinkDisplayColorMode_e::EinkDisplayColorModeStandard} {} EinkDisplay::~EinkDisplay() noexcept { - delete[] waveformSettings.LUTCData; - delete[] waveformSettings.LUTDData; + delete[] currentWaveform.LUTCData; + delete[] currentWaveform.LUTDData; } EinkStatus_e EinkDisplay::resetAndInit() @@ -85,27 +91,68 @@ namespace service::eink EinkBpp_e EinkDisplay::getCurrentBitsPerPixelFormat() const noexcept { - if ((waveformSettings.mode == EinkWaveformA2) || (waveformSettings.mode == EinkWaveformDU2)) { - return Eink4Bpp; /// this should be 1Bpp, but the OS is not ready for this + if ((currentWaveform.mode == EinkWaveformA2) || (currentWaveform.mode == EinkWaveformDU2)) { + return Eink4Bpp; // this should be 1Bpp, but the OS is not ready for this (in 1Bpp → halftones disappear) } return Eink4Bpp; } EinkStatus_e EinkDisplay::refresh(EinkDisplayTimingsMode_e refreshMode) { + currentWaveform.useCounter += 1; return EinkRefreshImage(pointTopLeft.x, pointTopLeft.y, size.width, size.height, refreshMode); } - bool EinkDisplay::changeWaveform(EinkWaveforms_e mode, std::int32_t temperature) + bool EinkDisplay::isNewWaveformNeeded(EinkWaveforms_e newMode, std::int32_t newTemperature) const + { + constexpr auto lenientTemperatureUseCounter = 50; // arbitrary. not documented + auto alloweLenientTemperature = currentWaveform.useCounter < lenientTemperatureUseCounter; + + // at least: modes cannot differ + if (alloweLenientTemperature && newMode == currentWaveform.mode) { + bool temperatureFine = false; + + switch (currentWaveform.mode) { + case EinkWaveformA2: + [[fallthrough]]; + case EinkWaveformDU2: + temperatureFine = abs(newTemperature - currentWaveform.temperature) <= 3; + break; + case EinkWaveformINIT: + [[fallthrough]]; + case EinkWaveformGLD16: + [[fallthrough]]; + case EinkWaveformGC16: + temperatureFine = abs(newTemperature - currentWaveform.temperature) <= 2; + break; + } + + if (temperatureFine) { + return false; + } + } + return true; + } + + bool EinkDisplay::setWaveform(EinkWaveforms_e mode, std::int32_t temperature) { - if (temperature == waveformSettings.temperature && mode == waveformSettings.mode) { - return EinkOK; + if (!isNewWaveformNeeded(mode, temperature)) { + return true; } - waveformSettings.temperature = temperature; - waveformSettings.mode = mode; - const auto segment = calculateWaveFormSegment(temperature); - auto offset = calculateWaveFormOffset(mode, segment); + auto currentOffset = + toWaveformOffset(currentWaveform.mode, toWaveformTemperatureOffset(currentWaveform.temperature)); + // assume it is changed + currentWaveform.useCounter = 0; + currentWaveform.temperature = temperature; + currentWaveform.mode = mode; + + auto offset = toWaveformOffset(mode, toWaveformTemperatureOffset(temperature)); + + if (offset == currentOffset) { + // current waveform is still the best fit + return true; + } auto file = std::fopen(LutsFileName, "rb"); if (file == nullptr) { @@ -114,62 +161,70 @@ namespace service::eink } auto fileHandlerCleanup = gsl::finally([&file]() { std::fclose(file); }); - resetWaveFormSettings(); + resetWaveformSettings(); std::fseek(file, offset, SEEK_SET); - std::fread(&waveformSettings.LUTDData[1], 1, LUTDSize, file); + std::fread(¤tWaveform.LUTDData[1], 1, LUTDSize, file); // 0x00 - 1 frame, ... , 0x0F - 16 frames - const uint8_t frameCount = waveformSettings.LUTDData[1] + 1; + const uint8_t waveformFrameCount = currentWaveform.LUTDData[1] + 1; // (frameCount * 64) - size of actual LUT; (+1) - the byte containing frameCount; (+1) - EinkLUTD command - waveformSettings.LUTDSize = (frameCount * 64) + 1 + 1; + currentWaveform.LUTDSize = (waveformFrameCount * 64) + 1 + 1; offset += LUTDSize; std::fseek(file, offset, SEEK_SET); - std::fread(&waveformSettings.LUTCData[1], 1, LUTCSize, file); + std::fread(¤tWaveform.LUTCData[1], 1, LUTCSize, file); - EinkUpdateWaveform(&waveformSettings); + EinkUpdateWaveform(¤tWaveform); return true; } - unsigned int EinkDisplay::calculateWaveFormSegment(std::int32_t temperature) const + unsigned int EinkDisplay::toWaveformTemperatureOffset(std::int32_t temperature) noexcept { - if (temperature < 38) { - return temperature / LUTVersionInterval; - } - if (temperature < 43) { - return LUTSubcritical; + if (temperature >= LUTTemperatureCritical) + return LUTTemperatureOffsetCritical; + if (temperature >= LUTTemperatureSubcritical) + return LUTTemperatureOffsetSubcritical; + if (temperature < LUTTemperatureMinimal) { + temperature = 0; } - return LUTCritical; + return temperature / LUTTemperatureOffsetInterval; + } + + unsigned int EinkDisplay::toWaveformOffset(unsigned short LUTbank, unsigned int temperatureOffset) noexcept + { + constexpr auto singleLUTOffset = (LUTTemperatureOffsetCritical + 1); + return LUTSTotalSize * (singleLUTOffset * LUTbank + temperatureOffset); } - unsigned int EinkDisplay::calculateWaveFormOffset(EinkWaveforms_e mode, unsigned int segment) const + unsigned int EinkDisplay::toWaveformOffset(EinkWaveforms_e mode, unsigned int temperatureOffset) { switch (mode) { case EinkWaveformINIT: - return LUTSTotalSize * segment; + return toWaveformOffset(0, temperatureOffset); case EinkWaveformA2: - return LUTSTotalSize * (14 + segment); + return toWaveformOffset(1, temperatureOffset); case EinkWaveformDU2: - return LUTSTotalSize * (28 + segment); + return toWaveformOffset(2, temperatureOffset); case EinkWaveformGLD16: - return LUTSTotalSize * (42 + segment); + return toWaveformOffset(3, temperatureOffset); case EinkWaveformGC16: - return LUTSTotalSize * (56 + segment); + return toWaveformOffset(4, temperatureOffset); + default: + throw std::invalid_argument{"Invalid waveform mode."}; } - throw std::invalid_argument{"Invalid waveform mode."}; } - void EinkDisplay::resetWaveFormSettings() + void EinkDisplay::resetWaveformSettings() { - delete[] waveformSettings.LUTDData; - waveformSettings.LUTDSize = 0; - waveformSettings.LUTDData = new std::uint8_t[LUTDSize + 1]; - waveformSettings.LUTDData[0] = EinkLUTD; + delete[] currentWaveform.LUTDData; + currentWaveform.LUTDSize = 0; + currentWaveform.LUTDData = new std::uint8_t[LUTDSize + 1]; + currentWaveform.LUTDData[0] = EinkLUTD; - delete[] waveformSettings.LUTCData; - waveformSettings.LUTCSize = LUTCSize; - waveformSettings.LUTCData = new std::uint8_t[LUTCSize + 1]; - waveformSettings.LUTCData[0] = EinkLUTC; + delete[] currentWaveform.LUTCData; + currentWaveform.LUTCSize = LUTCSize; + currentWaveform.LUTCData = new std::uint8_t[LUTCSize + 1]; + currentWaveform.LUTCData[0] = EinkLUTC; } void EinkDisplay::setMode(EinkDisplayColorMode_e mode) noexcept diff --git a/module-services/service-eink/EinkDisplay.hpp b/module-services/service-eink/EinkDisplay.hpp index b49aba82cd80adfdcb19d6e6dc7895d6b34e321d..80ae6859e9d8be4739061351d5ce7e8ebc3b3356 100644 --- a/module-services/service-eink/EinkDisplay.hpp +++ b/module-services/service-eink/EinkDisplay.hpp @@ -32,20 +32,22 @@ namespace service::eink void powerOff(); void shutdown(); - bool changeWaveform(EinkWaveforms_e mode, std::int32_t temperature); + bool setWaveform(EinkWaveforms_e mode, std::int32_t temperature); void setMode(EinkDisplayColorMode_e mode) noexcept; ::gui::Size getSize() const noexcept; private: - unsigned int calculateWaveFormSegment(std::int32_t temperature) const; - unsigned int calculateWaveFormOffset(EinkWaveforms_e mode, unsigned int segment) const; - void resetWaveFormSettings(); - EinkBpp_e getCurrentBitsPerPixelFormat() const noexcept; + static unsigned int toWaveformTemperatureOffset(std::int32_t temperature) noexcept; + static unsigned int toWaveformOffset(unsigned short LUTbank, unsigned int temperatureOffset) noexcept; + static unsigned int toWaveformOffset(EinkWaveforms_e mode, unsigned int temperatureOffset); + bool isNewWaveformNeeded(EinkWaveforms_e newMode, int32_t newTemperature) const; + void resetWaveformSettings(); + EinkBpp_e getCurrentBitsPerPixelFormat() const noexcept; static constexpr ::gui::Point pointTopLeft{0, 0}; const ::gui::Size size; - EinkWaveFormSettings_t waveformSettings; + EinkWaveformSettings_t currentWaveform; EinkDisplayColorMode_e displayMode; }; } // namespace service::eink diff --git a/module-services/service-eink/ServiceEink.cpp b/module-services/service-eink/ServiceEink.cpp index 9d93e1d28a08ab9603082e6cc0f5c7607b6f777c..8cd43671aceb1ffd6c3727351c2dc245e8a36ccd 100644 --- a/module-services/service-eink/ServiceEink.cpp +++ b/module-services/service-eink/ServiceEink.cpp @@ -3,9 +3,9 @@ #include "ServiceEink.hpp" #include "messages/EinkModeMessage.hpp" -#include "messages/PrepareDisplayRequest.hpp" +#include "messages/PrepareDisplayEarlyRequest.hpp" #include -#include +#include #include