Refactor power saving logic into display drivers and add ST7789 support
This commit is contained in:
@@ -56,6 +56,7 @@ add_executable(basic1
|
|||||||
games/lua_bindings.cpp
|
games/lua_bindings.cpp
|
||||||
games/lua_game_loader.cpp
|
games/lua_game_loader.cpp
|
||||||
lib/st7796/st7796.c
|
lib/st7796/st7796.c
|
||||||
|
lib/st7789/st7789.c
|
||||||
lib/ft6336u/ft6336u.c
|
lib/ft6336u/ft6336u.c
|
||||||
lib/sd_card/sd_card.c
|
lib/sd_card/sd_card.c
|
||||||
display/low_level_render.cpp
|
display/low_level_render.cpp
|
||||||
@@ -102,6 +103,7 @@ target_include_directories(basic1 PRIVATE
|
|||||||
${CMAKE_CURRENT_LIST_DIR}/lib/lua
|
${CMAKE_CURRENT_LIST_DIR}/lib/lua
|
||||||
${CMAKE_CURRENT_LIST_DIR}/lib/fatfs/source
|
${CMAKE_CURRENT_LIST_DIR}/lib/fatfs/source
|
||||||
${CMAKE_CURRENT_LIST_DIR}/lib/st7796
|
${CMAKE_CURRENT_LIST_DIR}/lib/st7796
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/lib/st7789
|
||||||
${CMAKE_CURRENT_LIST_DIR}/lib/ft6336u
|
${CMAKE_CURRENT_LIST_DIR}/lib/ft6336u
|
||||||
${CMAKE_CURRENT_LIST_DIR}/lib/sd_card
|
${CMAKE_CURRENT_LIST_DIR}/lib/sd_card
|
||||||
${CMAKE_CURRENT_LIST_DIR}/display
|
${CMAKE_CURRENT_LIST_DIR}/display
|
||||||
|
|||||||
97
basic1.cpp
97
basic1.cpp
@@ -160,56 +160,31 @@ struct GameConfig {
|
|||||||
#define DIM_TIMEOUT_MS (2 * 60 * 1000) // 2 minutes to dim
|
#define DIM_TIMEOUT_MS (2 * 60 * 1000) // 2 minutes to dim
|
||||||
#define SLEEP_TIMEOUT_MS (10 * 60 * 1000) // 10 minutes to sleep
|
#define SLEEP_TIMEOUT_MS (10 * 60 * 1000) // 10 minutes to sleep
|
||||||
#define DIM_CHECK_INTERVAL_MS 10000 // Check every 10 seconds
|
#define DIM_CHECK_INTERVAL_MS 10000 // Check every 10 seconds
|
||||||
#define DIM_BRIGHTNESS 5 // Dimmed brightness level (0-100)
|
|
||||||
#define NORMAL_BRIGHTNESS 100 // Normal brightness level (0-100)
|
|
||||||
|
|
||||||
// Display dimming state
|
// Display dimming state
|
||||||
static uint32_t last_interaction_time = 0; // Last time user interacted
|
static uint32_t last_interaction_time = 0; // Last time user interacted
|
||||||
static bool is_dimmed = false; // Current dimming state
|
static bool is_idle_2min_triggered = false; // Flag for 2min trigger
|
||||||
static bool is_sleeping = false; // Current sleep state
|
static bool is_idle_10min_triggered = false; // Flag for 10min trigger
|
||||||
static uint8_t saved_brightness = NORMAL_BRIGHTNESS; // Brightness before dimming
|
|
||||||
static volatile bool dim_check_flag = false; // Flag set by timer to check dimming
|
static volatile bool dim_check_flag = false; // Flag set by timer to check dimming
|
||||||
static LowLevelDisplay* global_display = nullptr; // Global display pointer for timer callback
|
static LowLevelDisplay* global_display = nullptr; // Global display pointer for timer callback
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Update last interaction time and restore display if dimmed
|
* @brief Update last interaction time and notify display driver
|
||||||
*
|
*
|
||||||
* Call this whenever the user interacts with the device (touch, button press)
|
* Call this whenever the user interacts with the device (touch, button press).
|
||||||
* to reset the dimming timer and restore display if it was dimmed/sleeping.
|
* The display driver handles specific wake/restore logic.
|
||||||
*
|
|
||||||
* For TFT displays: Restores brightness level
|
|
||||||
* For e-ink displays: Wakes display from sleep and refreshes screen
|
|
||||||
*
|
*
|
||||||
* @param display Pointer to display interface
|
* @param display Pointer to display interface
|
||||||
*/
|
*/
|
||||||
static inline void record_user_interaction(LowLevelDisplay* display) {
|
static inline void record_user_interaction(LowLevelDisplay* display) {
|
||||||
last_interaction_time = to_ms_since_boot(get_absolute_time());
|
last_interaction_time = to_ms_since_boot(get_absolute_time());
|
||||||
|
|
||||||
// If display was sleeping, wake it up
|
// Reset idle flags
|
||||||
if (is_sleeping) {
|
is_idle_2min_triggered = false;
|
||||||
if (display->get_type() == DISPLAY_TYPE_ST7796) {
|
is_idle_10min_triggered = false;
|
||||||
LowLevelDisplayST7796* tft = static_cast<LowLevelDisplayST7796*>(display);
|
|
||||||
tft->wake();
|
// Notify display driver of interaction
|
||||||
tft->set_brightness(saved_brightness);
|
display->on_user_interaction();
|
||||||
printf("TFT display woken from sleep\n");
|
|
||||||
} else if (display->get_type() == DISPLAY_TYPE_EPAPER) {
|
|
||||||
printf("Waking e-paper display from sleep...\n");
|
|
||||||
LowLevelDisplayEPaper* epaper = static_cast<LowLevelDisplayEPaper*>(display);
|
|
||||||
epaper->init();
|
|
||||||
printf("E-paper display ready\n");
|
|
||||||
}
|
|
||||||
is_sleeping = false;
|
|
||||||
is_dimmed = false;
|
|
||||||
}
|
|
||||||
// If display was dimmed, restore brightness
|
|
||||||
else if (is_dimmed) {
|
|
||||||
if (display->get_type() == DISPLAY_TYPE_ST7796) {
|
|
||||||
LowLevelDisplayST7796* tft = static_cast<LowLevelDisplayST7796*>(display);
|
|
||||||
tft->set_brightness(saved_brightness);
|
|
||||||
printf("TFT display brightness restored\n");
|
|
||||||
}
|
|
||||||
is_dimmed = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -233,12 +208,10 @@ static int64_t dim_check_alarm_callback(alarm_id_t id, void *user_data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Check if display should be dimmed and apply dimming if needed
|
* @brief Check if idle thresholds have been met and notify display driver
|
||||||
*
|
*
|
||||||
* Checks if the timeout has elapsed since last interaction and dims/sleeps
|
* Checks elapsed time since last interaction and calls the appropriate
|
||||||
* the display based on its type:
|
* display driver methods (on_idle_2min or on_idle_10min).
|
||||||
* - TFT displays (ST7796): Reduces brightness to minimum
|
|
||||||
* - E-ink displays: Puts display to sleep mode (turns off)
|
|
||||||
*
|
*
|
||||||
* @param display Pointer to display interface
|
* @param display Pointer to display interface
|
||||||
*/
|
*/
|
||||||
@@ -246,33 +219,16 @@ static inline void check_and_apply_dimming(LowLevelDisplay* display) {
|
|||||||
uint32_t current_time = to_ms_since_boot(get_absolute_time());
|
uint32_t current_time = to_ms_since_boot(get_absolute_time());
|
||||||
uint32_t elapsed = current_time - last_interaction_time;
|
uint32_t elapsed = current_time - last_interaction_time;
|
||||||
|
|
||||||
// Check for sleep timeout
|
// Check for 10 minute timeout (Sleep)
|
||||||
if (!is_sleeping && elapsed >= SLEEP_TIMEOUT_MS) {
|
if (!is_idle_10min_triggered && elapsed >= SLEEP_TIMEOUT_MS) {
|
||||||
if (display->get_type() == DISPLAY_TYPE_ST7796) {
|
display->on_idle_10min();
|
||||||
LowLevelDisplayST7796* tft = static_cast<LowLevelDisplayST7796*>(display);
|
is_idle_10min_triggered = true;
|
||||||
tft->sleep();
|
is_idle_2min_triggered = true; // Implicitly triggered
|
||||||
printf("TFT display put to sleep after %d minutes of inactivity\n",
|
|
||||||
SLEEP_TIMEOUT_MS / 60000);
|
|
||||||
} else if (display->get_type() == DISPLAY_TYPE_EPAPER) {
|
|
||||||
LowLevelDisplayEPaper* epaper = static_cast<LowLevelDisplayEPaper*>(display);
|
|
||||||
epaper->sleep();
|
|
||||||
printf("E-paper display put to sleep after %d minutes of inactivity\n",
|
|
||||||
SLEEP_TIMEOUT_MS / 60000);
|
|
||||||
}
|
}
|
||||||
is_sleeping = true;
|
// Check for 2 minute timeout (Dim)
|
||||||
is_dimmed = true; // Sleep implies dimmed state
|
else if (!is_idle_2min_triggered && elapsed >= DIM_TIMEOUT_MS) {
|
||||||
}
|
display->on_idle_2min();
|
||||||
// Check for dim timeout
|
is_idle_2min_triggered = true;
|
||||||
else if (!is_dimmed && !is_sleeping && elapsed >= DIM_TIMEOUT_MS) {
|
|
||||||
if (display->get_type() == DISPLAY_TYPE_ST7796) {
|
|
||||||
saved_brightness = display->get_brightness();
|
|
||||||
LowLevelDisplayST7796* tft = static_cast<LowLevelDisplayST7796*>(display);
|
|
||||||
tft->set_brightness(DIM_BRIGHTNESS);
|
|
||||||
printf("TFT display dimmed after %d minutes of inactivity\n",
|
|
||||||
DIM_TIMEOUT_MS / 60000);
|
|
||||||
}
|
|
||||||
// E-paper doesn't support dimming, so we skip it until sleep timeout
|
|
||||||
is_dimmed = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -582,11 +538,10 @@ int main()
|
|||||||
add_alarm_in_ms(DIM_CHECK_INTERVAL_MS, dim_check_alarm_callback, nullptr, true);
|
add_alarm_in_ms(DIM_CHECK_INTERVAL_MS, dim_check_alarm_callback, nullptr, true);
|
||||||
|
|
||||||
if (display->get_type() == DISPLAY_TYPE_ST7796) {
|
if (display->get_type() == DISPLAY_TYPE_ST7796) {
|
||||||
printf("Power saving enabled: Dim after %d min, Sleep after %d min\n",
|
printf("Power saving: Dim at %d min, Sleep at %d min\n",
|
||||||
DIM_TIMEOUT_MS / 60000, SLEEP_TIMEOUT_MS / 60000);
|
DIM_TIMEOUT_MS / 60000, SLEEP_TIMEOUT_MS / 60000);
|
||||||
} else if (display->get_type() == DISPLAY_TYPE_EPAPER) {
|
} else {
|
||||||
printf("Auto-sleep enabled: E-paper will sleep after %d minutes of inactivity\n",
|
printf("Power saving: Sleep at %d min\n", SLEEP_TIMEOUT_MS / 60000);
|
||||||
SLEEP_TIMEOUT_MS / 60000);
|
|
||||||
}
|
}
|
||||||
printf("Dimming check timer set to %d seconds\n", DIM_CHECK_INTERVAL_MS / 1000);
|
printf("Dimming check timer set to %d seconds\n", DIM_CHECK_INTERVAL_MS / 1000);
|
||||||
|
|
||||||
|
|||||||
@@ -40,6 +40,11 @@ public:
|
|||||||
// Optional: Orientation control (not commonly needed for bitmap displays)
|
// Optional: Orientation control (not commonly needed for bitmap displays)
|
||||||
virtual void set_rotation(uint8_t rotation) { (void)rotation; }
|
virtual void set_rotation(uint8_t rotation) { (void)rotation; }
|
||||||
|
|
||||||
|
// Power saving hooks
|
||||||
|
virtual void on_idle_2min() {}
|
||||||
|
virtual void on_idle_10min() {}
|
||||||
|
virtual void on_user_interaction() {}
|
||||||
|
|
||||||
// Factory method - creates display based on type, using board_config.h for pins
|
// Factory method - creates display based on type, using board_config.h for pins
|
||||||
static LowLevelDisplay* create(DisplayType type, int width, int height);
|
static LowLevelDisplay* create(DisplayType type, int width, int height);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -141,3 +141,24 @@ void LowLevelDisplayEPaper::sleep() {
|
|||||||
printf("Putting e-paper display to sleep...\n");
|
printf("Putting e-paper display to sleep...\n");
|
||||||
EPD_4IN2_V2_Sleep();
|
EPD_4IN2_V2_Sleep();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LowLevelDisplayEPaper::on_idle_2min() {
|
||||||
|
// E-paper doesn't dim
|
||||||
|
}
|
||||||
|
|
||||||
|
void LowLevelDisplayEPaper::on_idle_10min() {
|
||||||
|
if (!is_sleeping) {
|
||||||
|
sleep();
|
||||||
|
is_sleeping = true;
|
||||||
|
printf("E-Paper: Entered sleep mode\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LowLevelDisplayEPaper::on_user_interaction() {
|
||||||
|
if (is_sleeping) {
|
||||||
|
printf("E-Paper: Waking from sleep...\n");
|
||||||
|
init(); // Re-initialize to wake up
|
||||||
|
is_sleeping = false;
|
||||||
|
printf("E-Paper: Ready\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -44,6 +44,14 @@ public:
|
|||||||
void clear_display(); // Full clear with refresh
|
void clear_display(); // Full clear with refresh
|
||||||
void full_refresh(); // Force full screen refresh (slower but removes ghosting)
|
void full_refresh(); // Force full screen refresh (slower but removes ghosting)
|
||||||
void sleep(); // Put display in low power mode
|
void sleep(); // Put display in low power mode
|
||||||
|
|
||||||
|
// Power saving hooks
|
||||||
|
void on_idle_2min() override;
|
||||||
|
void on_idle_10min() override;
|
||||||
|
void on_user_interaction() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool is_sleeping = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // LOW_LEVEL_DISPLAY_EPAPER_H
|
#endif // LOW_LEVEL_DISPLAY_EPAPER_H
|
||||||
|
|||||||
@@ -69,11 +69,51 @@ void LowLevelDisplayST7789::refresh() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void LowLevelDisplayST7789::set_backlight(bool on) {
|
void LowLevelDisplayST7789::set_backlight(bool on) {
|
||||||
// TODO: Implement
|
set_brightness(on ? 100 : 0);
|
||||||
(void)on;
|
}
|
||||||
|
|
||||||
|
void LowLevelDisplayST7789::set_brightness(uint8_t brightness) {
|
||||||
|
st7789_set_brightness(brightness);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t LowLevelDisplayST7789::get_brightness() const {
|
||||||
|
return st7789_get_brightness();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LowLevelDisplayST7789::set_rotation(uint8_t rotation) {
|
void LowLevelDisplayST7789::set_rotation(uint8_t rotation) {
|
||||||
// TODO: Implement
|
// TODO: Implement
|
||||||
(void)rotation;
|
(void)rotation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LowLevelDisplayST7789::on_idle_2min() {
|
||||||
|
if (!is_dimmed && !is_sleeping) {
|
||||||
|
saved_brightness = get_brightness();
|
||||||
|
set_brightness(5); // Dim to 5%
|
||||||
|
is_dimmed = true;
|
||||||
|
printf("ST7789: Dimmed to 5%%\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LowLevelDisplayST7789::on_idle_10min() {
|
||||||
|
if (!is_sleeping) {
|
||||||
|
st7789_sleep();
|
||||||
|
is_sleeping = true;
|
||||||
|
is_dimmed = true; // Sleep implies dimmed
|
||||||
|
printf("ST7789: Entered sleep mode\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LowLevelDisplayST7789::on_user_interaction() {
|
||||||
|
if (is_sleeping) {
|
||||||
|
st7789_wake();
|
||||||
|
// Restore brightness if we have a saved value, or default to 100
|
||||||
|
set_brightness(saved_brightness > 0 ? saved_brightness : 100);
|
||||||
|
is_sleeping = false;
|
||||||
|
is_dimmed = false;
|
||||||
|
printf("ST7789: Woke from sleep\n");
|
||||||
|
} else if (is_dimmed) {
|
||||||
|
set_brightness(saved_brightness > 0 ? saved_brightness : 100);
|
||||||
|
is_dimmed = false;
|
||||||
|
printf("ST7789: Restored brightness\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,17 +2,7 @@
|
|||||||
#define LOW_LEVEL_DISPLAY_ST7789_H
|
#define LOW_LEVEL_DISPLAY_ST7789_H
|
||||||
|
|
||||||
#include "low_level_display.h"
|
#include "low_level_display.h"
|
||||||
|
#include "st7789.h"
|
||||||
// ST7789 configuration structure (similar to ST7796)
|
|
||||||
struct st7789_config {
|
|
||||||
void* spi; // SPI instance
|
|
||||||
int gpio_din; // MOSI pin
|
|
||||||
int gpio_clk; // Clock pin
|
|
||||||
int gpio_cs; // Chip select pin
|
|
||||||
int gpio_dc; // Data/Command pin
|
|
||||||
int gpio_rst; // Reset pin
|
|
||||||
int gpio_bl; // Backlight pin
|
|
||||||
};
|
|
||||||
|
|
||||||
class LowLevelDisplayST7789 : public LowLevelDisplay {
|
class LowLevelDisplayST7789 : public LowLevelDisplay {
|
||||||
private:
|
private:
|
||||||
@@ -42,8 +32,22 @@ public:
|
|||||||
// Backlight control
|
// Backlight control
|
||||||
void set_backlight(bool on) override;
|
void set_backlight(bool on) override;
|
||||||
|
|
||||||
|
// Brightness control
|
||||||
|
void set_brightness(uint8_t brightness) override;
|
||||||
|
uint8_t get_brightness() const override;
|
||||||
|
|
||||||
// Orientation control
|
// Orientation control
|
||||||
void set_rotation(uint8_t rotation) override;
|
void set_rotation(uint8_t rotation) override;
|
||||||
|
|
||||||
|
// Power saving hooks
|
||||||
|
void on_idle_2min() override;
|
||||||
|
void on_idle_10min() override;
|
||||||
|
void on_user_interaction() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8_t saved_brightness = 100;
|
||||||
|
bool is_dimmed = false;
|
||||||
|
bool is_sleeping = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // LOW_LEVEL_DISPLAY_ST7789_H
|
#endif // LOW_LEVEL_DISPLAY_ST7789_H
|
||||||
|
|||||||
@@ -94,3 +94,36 @@ void LowLevelDisplayST7796::set_rotation(uint8_t rotation) {
|
|||||||
// TODO: Add MADCTL register manipulation for rotation
|
// TODO: Add MADCTL register manipulation for rotation
|
||||||
(void)rotation;
|
(void)rotation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LowLevelDisplayST7796::on_idle_2min() {
|
||||||
|
if (!is_dimmed && !is_sleeping) {
|
||||||
|
saved_brightness = get_brightness();
|
||||||
|
set_brightness(5); // Dim to 5%
|
||||||
|
is_dimmed = true;
|
||||||
|
printf("TFT: Dimmed to 5%%\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LowLevelDisplayST7796::on_idle_10min() {
|
||||||
|
if (!is_sleeping) {
|
||||||
|
sleep();
|
||||||
|
is_sleeping = true;
|
||||||
|
is_dimmed = true; // Sleep implies dimmed
|
||||||
|
printf("TFT: Entered sleep mode\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LowLevelDisplayST7796::on_user_interaction() {
|
||||||
|
if (is_sleeping) {
|
||||||
|
wake();
|
||||||
|
// Restore brightness if we have a saved value, or default to 100
|
||||||
|
set_brightness(saved_brightness > 0 ? saved_brightness : 100);
|
||||||
|
is_sleeping = false;
|
||||||
|
is_dimmed = false;
|
||||||
|
printf("TFT: Woke from sleep\n");
|
||||||
|
} else if (is_dimmed) {
|
||||||
|
set_brightness(saved_brightness > 0 ? saved_brightness : 100);
|
||||||
|
is_dimmed = false;
|
||||||
|
printf("TFT: Restored brightness\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -47,6 +47,16 @@ public:
|
|||||||
// Color inversion control
|
// Color inversion control
|
||||||
void set_invert_color(bool inv) { invert_color = inv; }
|
void set_invert_color(bool inv) { invert_color = inv; }
|
||||||
bool get_invert_color() const { return invert_color; }
|
bool get_invert_color() const { return invert_color; }
|
||||||
|
|
||||||
|
// Power saving hooks
|
||||||
|
void on_idle_2min() override;
|
||||||
|
void on_idle_10min() override;
|
||||||
|
void on_user_interaction() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8_t saved_brightness = 100;
|
||||||
|
bool is_dimmed = false;
|
||||||
|
bool is_sleeping = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // LOW_LEVEL_DISPLAY_ST7796_H
|
#endif // LOW_LEVEL_DISPLAY_ST7796_H
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
#include "hardware/gpio.h"
|
#include "hardware/gpio.h"
|
||||||
#include "hardware/spi.h"
|
#include "hardware/spi.h"
|
||||||
|
#include "hardware/pwm.h"
|
||||||
#include "pico/binary_info.h"
|
#include "pico/binary_info.h"
|
||||||
#include "pico/stdlib.h"
|
#include "pico/stdlib.h"
|
||||||
|
|
||||||
@@ -60,6 +61,12 @@ static uint16_t height;
|
|||||||
static uint16_t x_offset;
|
static uint16_t x_offset;
|
||||||
static uint16_t y_offset;
|
static uint16_t y_offset;
|
||||||
|
|
||||||
|
// Backlight control
|
||||||
|
static uint pwm_slice;
|
||||||
|
static uint pwm_channel;
|
||||||
|
static uint8_t current_brightness = 100;
|
||||||
|
static bool pwm_initialized = false;
|
||||||
|
|
||||||
static inline void cs_select() {
|
static inline void cs_select() {
|
||||||
if (config->gpio_cs >= 0) {
|
if (config->gpio_cs >= 0) {
|
||||||
asm volatile("nop \n nop \n nop");
|
asm volatile("nop \n nop \n nop");
|
||||||
@@ -173,10 +180,19 @@ void st7789_init(const struct st7789_config *c, uint16_t w, uint16_t h) {
|
|||||||
gpio_init(config->gpio_rst);
|
gpio_init(config->gpio_rst);
|
||||||
gpio_set_dir(config->gpio_rst, GPIO_OUT);
|
gpio_set_dir(config->gpio_rst, GPIO_OUT);
|
||||||
|
|
||||||
// Initialize backlight pin
|
// Initialize backlight pin with PWM
|
||||||
gpio_init(config->gpio_bl);
|
if (config->gpio_bl >= 0) {
|
||||||
gpio_set_dir(config->gpio_bl, GPIO_OUT);
|
gpio_set_function(config->gpio_bl, GPIO_FUNC_PWM);
|
||||||
gpio_put(config->gpio_bl, 1); // Turn on backlight
|
pwm_slice = pwm_gpio_to_slice_num(config->gpio_bl);
|
||||||
|
pwm_channel = pwm_gpio_to_channel(config->gpio_bl);
|
||||||
|
|
||||||
|
// Set PWM frequency to ~1kHz
|
||||||
|
pwm_set_wrap(pwm_slice, 65535);
|
||||||
|
pwm_set_chan_level(pwm_slice, pwm_channel, 65535); // 100% duty cycle
|
||||||
|
pwm_set_enabled(pwm_slice, true);
|
||||||
|
|
||||||
|
pwm_initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
// Reset display
|
// Reset display
|
||||||
reset_pulse();
|
reset_pulse();
|
||||||
@@ -403,3 +419,48 @@ void st7789_draw_line(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void st7789_set_brightness(uint8_t brightness) {
|
||||||
|
if (!pwm_initialized || config->gpio_bl < 0) return;
|
||||||
|
|
||||||
|
// Clamp brightness
|
||||||
|
if (brightness > 100) brightness = 100;
|
||||||
|
|
||||||
|
current_brightness = brightness;
|
||||||
|
|
||||||
|
// Convert 0-100 to 0-65535
|
||||||
|
uint16_t level = (uint16_t)((brightness * 65535) / 100);
|
||||||
|
pwm_set_chan_level(pwm_slice, pwm_channel, level);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t st7789_get_brightness(void) {
|
||||||
|
return current_brightness;
|
||||||
|
}
|
||||||
|
|
||||||
|
void st7789_sleep(void) {
|
||||||
|
// Turn off backlight
|
||||||
|
if (pwm_initialized && config->gpio_bl >= 0) {
|
||||||
|
pwm_set_chan_level(pwm_slice, pwm_channel, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display off
|
||||||
|
write_command(ST7789_DISPOFF);
|
||||||
|
sleep_ms(10);
|
||||||
|
|
||||||
|
// Sleep in
|
||||||
|
write_command(ST7789_SLPIN);
|
||||||
|
sleep_ms(120);
|
||||||
|
}
|
||||||
|
|
||||||
|
void st7789_wake(void) {
|
||||||
|
// Sleep out
|
||||||
|
write_command(ST7789_SLPOUT);
|
||||||
|
sleep_ms(120);
|
||||||
|
|
||||||
|
// Display on
|
||||||
|
write_command(ST7789_DISPON);
|
||||||
|
sleep_ms(10);
|
||||||
|
|
||||||
|
// Restore brightness
|
||||||
|
st7789_set_brightness(current_brightness);
|
||||||
|
}
|
||||||
|
|||||||
@@ -38,6 +38,11 @@ void st7789_draw_circle(uint16_t x0, uint16_t y0, uint16_t r, uint16_t color);
|
|||||||
void st7789_fill_circle(uint16_t x0, uint16_t y0, uint16_t r, uint16_t color);
|
void st7789_fill_circle(uint16_t x0, uint16_t y0, uint16_t r, uint16_t color);
|
||||||
void st7789_draw_line(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t color);
|
void st7789_draw_line(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t color);
|
||||||
|
|
||||||
|
void st7789_sleep(void);
|
||||||
|
void st7789_wake(void);
|
||||||
|
void st7789_set_brightness(uint8_t brightness);
|
||||||
|
uint8_t st7789_get_brightness(void);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user