Improve handling of the display

- Blank the display when locking to prevent burn-in
 - Delay turning the display on until *exactly* after the first lvgl flush
 - Init the display in the ui task to avoid blocking the rest of boot
custom
jacqueline 1 year ago
parent 5b99267cb9
commit db9e5cce1f
  1. 28
      src/drivers/display.cpp
  2. 1
      src/drivers/include/display.hpp
  3. 7
      src/ui/include/ui_events.hpp
  4. 1
      src/ui/include/ui_fsm.hpp
  5. 1
      src/ui/lvgl_task.cpp
  6. 23
      src/ui/ui_fsm.cpp

@ -5,6 +5,7 @@
*/ */
#include "display.hpp" #include "display.hpp"
#include <stdint.h>
#include <cmath> #include <cmath>
#include <cstdint> #include <cstdint>
@ -168,7 +169,11 @@ auto Display::Create(IGpios& expander,
} }
Display::Display(IGpios& gpio, spi_device_handle_t handle) Display::Display(IGpios& gpio, spi_device_handle_t handle)
: gpio_(gpio), handle_(handle), display_on_(false), brightness_(0) {} : gpio_(gpio),
handle_(handle),
first_flush_finished_(false),
display_on_(false),
brightness_(0) {}
Display::~Display() { Display::~Display() {
ledc_fade_func_uninstall(); ledc_fade_func_uninstall();
@ -176,14 +181,28 @@ Display::~Display() {
auto Display::SetDisplayOn(bool enabled) -> void { auto Display::SetDisplayOn(bool enabled) -> void {
display_on_ = enabled; display_on_ = enabled;
if (!first_flush_finished_) {
return;
}
if (display_on_) {
SendCommandWithData(displays::ST77XX_DISPON, nullptr, 0);
vTaskDelay(pdMS_TO_TICKS(100));
}
int new_duty = display_on_ ? brightness_ : 0; int new_duty = display_on_ ? brightness_ : 0;
SetDutyCycle(new_duty, true); SetDutyCycle(new_duty, true);
if (!display_on_) {
vTaskDelay(pdMS_TO_TICKS(100));
SendCommandWithData(displays::ST77XX_DISPOFF, nullptr, 0);
}
} }
auto Display::SetBrightness(uint_fast8_t percent) -> void { auto Display::SetBrightness(uint_fast8_t percent) -> void {
brightness_ = brightness_ =
std::pow(static_cast<double>(percent) / 100.0, 2.8) * 1024.0 + 0.5; std::pow(static_cast<double>(percent) / 100.0, 2.8) * 1024.0 + 0.5;
if (display_on_) { if (first_flush_finished_ && display_on_) {
SetDutyCycle(brightness_, false); SetDutyCycle(brightness_, false);
} }
} }
@ -295,6 +314,11 @@ void Display::OnLvglFlush(lv_disp_drv_t* disp_drv,
SendCommandWithData(displays::ST77XX_RAMWR, SendCommandWithData(displays::ST77XX_RAMWR,
reinterpret_cast<uint8_t*>(color_map), size * 2); reinterpret_cast<uint8_t*>(color_map), size * 2);
if (!first_flush_finished_ && lv_disp_flush_is_last(disp_drv)) {
first_flush_finished_ = true;
SetDisplayOn(display_on_);
}
lv_disp_flush_ready(&driver_); lv_disp_flush_ready(&driver_);
} }

@ -52,6 +52,7 @@ class Display {
IGpios& gpio_; IGpios& gpio_;
spi_device_handle_t handle_; spi_device_handle_t handle_;
bool first_flush_finished_;
bool display_on_; bool display_on_;
uint_fast8_t brightness_; uint_fast8_t brightness_;

@ -8,7 +8,9 @@
#include <memory> #include <memory>
#include "database.hpp" #include "database.hpp"
#include "gpios.hpp"
#include "index.hpp" #include "index.hpp"
#include "nvs.hpp"
#include "screen.hpp" #include "screen.hpp"
#include "tinyfsm.hpp" #include "tinyfsm.hpp"
@ -32,6 +34,11 @@ struct DumpLuaStack : tinyfsm::Event {};
namespace internal { namespace internal {
struct InitDisplay : tinyfsm::Event {
drivers::IGpios& gpios;
drivers::NvsStorage& nvs;
};
struct ReindexDatabase : tinyfsm::Event {}; struct ReindexDatabase : tinyfsm::Event {};
struct BackPressed : tinyfsm::Event {}; struct BackPressed : tinyfsm::Event {};

@ -70,6 +70,7 @@ class UiState : public tinyfsm::Fsm<UiState> {
void react(const system_fsm::KeyLockChanged&); void react(const system_fsm::KeyLockChanged&);
void react(const system_fsm::SamdUsbStatusChanged&); void react(const system_fsm::SamdUsbStatusChanged&);
void react(const internal::InitDisplay&);
void react(const internal::DismissAlerts&); void react(const internal::DismissAlerts&);
void react(const database::event::UpdateStarted&); void react(const database::event::UpdateStarted&);

@ -84,7 +84,6 @@ auto UiTask::Main() -> void {
} }
auto UiTask::input(std::shared_ptr<input::LvglInputDriver> input) -> void { auto UiTask::input(std::shared_ptr<input::LvglInputDriver> input) -> void {
assert(current_screen_);
input_ = input; input_ = input;
} }

@ -267,6 +267,15 @@ lua::Property UiState::sUsbMassStorageBusy{false};
auto UiState::InitBootSplash(drivers::IGpios& gpios, drivers::NvsStorage& nvs) auto UiState::InitBootSplash(drivers::IGpios& gpios, drivers::NvsStorage& nvs)
-> bool { -> bool {
events::Ui().Dispatch(internal::InitDisplay{
.gpios = gpios,
.nvs = nvs,
});
sTask.reset(UiTask::Start());
return true;
}
void UiState::react(const internal::InitDisplay& ev) {
// Init LVGL first, since the display driver registers itself with LVGL. // Init LVGL first, since the display driver registers itself with LVGL.
lv_init(); lv_init();
@ -275,19 +284,15 @@ auto UiState::InitBootSplash(drivers::IGpios& gpios, drivers::NvsStorage& nvs)
// HACK: correct the display size for our prototypes. // HACK: correct the display size for our prototypes.
// nvs.DisplaySize({161, 130}); // nvs.DisplaySize({161, 130});
auto actual_size = nvs.DisplaySize(); auto actual_size = ev.nvs.DisplaySize();
init_data.width = actual_size.first.value_or(init_data.width); init_data.width = actual_size.first.value_or(init_data.width);
init_data.height = actual_size.second.value_or(init_data.height); init_data.height = actual_size.second.value_or(init_data.height);
sDisplay.reset(drivers::Display::Create(ev.gpios, init_data));
sDisplay.reset(drivers::Display::Create(gpios, init_data));
if (sDisplay == nullptr) {
return false;
}
sCurrentScreen.reset(new screens::Splash()); sCurrentScreen.reset(new screens::Splash());
sTask.reset(UiTask::Start());
sDisplay->SetDisplayOn(!gpios.IsLocked()); // Display will only actually come on after LVGL finishes its first flush.
return true; sDisplay->SetDisplayOn(!ev.gpios.IsLocked());
} }
void UiState::PushScreen(std::shared_ptr<Screen> screen) { void UiState::PushScreen(std::shared_ptr<Screen> screen) {

Loading…
Cancel
Save