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
This commit is contained in:
+26
-2
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
#include "display.hpp"
|
||||
#include <stdint.h>
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
@@ -168,7 +169,11 @@ auto Display::Create(IGpios& expander,
|
||||
}
|
||||
|
||||
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() {
|
||||
ledc_fade_func_uninstall();
|
||||
@@ -176,14 +181,28 @@ Display::~Display() {
|
||||
|
||||
auto Display::SetDisplayOn(bool enabled) -> void {
|
||||
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;
|
||||
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 {
|
||||
brightness_ =
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -295,6 +314,11 @@ void Display::OnLvglFlush(lv_disp_drv_t* disp_drv,
|
||||
SendCommandWithData(displays::ST77XX_RAMWR,
|
||||
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_);
|
||||
}
|
||||
|
||||
|
||||
@@ -52,6 +52,7 @@ class Display {
|
||||
IGpios& gpio_;
|
||||
spi_device_handle_t handle_;
|
||||
|
||||
bool first_flush_finished_;
|
||||
bool display_on_;
|
||||
uint_fast8_t brightness_;
|
||||
|
||||
|
||||
@@ -8,7 +8,9 @@
|
||||
|
||||
#include <memory>
|
||||
#include "database.hpp"
|
||||
#include "gpios.hpp"
|
||||
#include "index.hpp"
|
||||
#include "nvs.hpp"
|
||||
#include "screen.hpp"
|
||||
#include "tinyfsm.hpp"
|
||||
|
||||
@@ -32,6 +34,11 @@ struct DumpLuaStack : tinyfsm::Event {};
|
||||
|
||||
namespace internal {
|
||||
|
||||
struct InitDisplay : tinyfsm::Event {
|
||||
drivers::IGpios& gpios;
|
||||
drivers::NvsStorage& nvs;
|
||||
};
|
||||
|
||||
struct ReindexDatabase : 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::SamdUsbStatusChanged&);
|
||||
|
||||
void react(const internal::InitDisplay&);
|
||||
void react(const internal::DismissAlerts&);
|
||||
|
||||
void react(const database::event::UpdateStarted&);
|
||||
|
||||
@@ -84,7 +84,6 @@ auto UiTask::Main() -> void {
|
||||
}
|
||||
|
||||
auto UiTask::input(std::shared_ptr<input::LvglInputDriver> input) -> void {
|
||||
assert(current_screen_);
|
||||
input_ = input;
|
||||
}
|
||||
|
||||
|
||||
+14
-9
@@ -267,6 +267,15 @@ lua::Property UiState::sUsbMassStorageBusy{false};
|
||||
|
||||
auto UiState::InitBootSplash(drivers::IGpios& gpios, drivers::NvsStorage& nvs)
|
||||
-> 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.
|
||||
lv_init();
|
||||
|
||||
@@ -275,19 +284,15 @@ auto UiState::InitBootSplash(drivers::IGpios& gpios, drivers::NvsStorage& nvs)
|
||||
// HACK: correct the display size for our prototypes.
|
||||
// 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.height = actual_size.second.value_or(init_data.height);
|
||||
|
||||
sDisplay.reset(drivers::Display::Create(gpios, init_data));
|
||||
if (sDisplay == nullptr) {
|
||||
return false;
|
||||
}
|
||||
sDisplay.reset(drivers::Display::Create(ev.gpios, init_data));
|
||||
|
||||
sCurrentScreen.reset(new screens::Splash());
|
||||
sTask.reset(UiTask::Start());
|
||||
sDisplay->SetDisplayOn(!gpios.IsLocked());
|
||||
return true;
|
||||
|
||||
// Display will only actually come on after LVGL finishes its first flush.
|
||||
sDisplay->SetDisplayOn(!ev.gpios.IsLocked());
|
||||
}
|
||||
|
||||
void UiState::PushScreen(std::shared_ptr<Screen> screen) {
|
||||
|
||||
Reference in New Issue
Block a user