mirror of
https://github.com/pelgraine/Meck.git
synced 2026-03-28 17:42:44 +01:00
tdpro & t5s3 pro - lock screen power saving improvements; fix stupid stupid merged firmware - bug
This commit is contained in:
@@ -1662,6 +1662,27 @@ void loop() {
|
|||||||
// CPU frequency auto-timeout back to idle
|
// CPU frequency auto-timeout back to idle
|
||||||
cpuPower.loop();
|
cpuPower.loop();
|
||||||
|
|
||||||
|
// Low-power mode — drop CPU to 40 MHz and throttle loop when lock screen
|
||||||
|
// is active. The mesh radio has its own FIFO so packets are buffered;
|
||||||
|
// 50 ms yield means the loop still runs 20×/sec which is more than enough
|
||||||
|
// to drain the radio FIFO before overflow.
|
||||||
|
#if defined(LilyGo_T5S3_EPaper_Pro) || defined(LilyGo_TDeck_Pro)
|
||||||
|
{
|
||||||
|
static bool wasLocked = false;
|
||||||
|
bool nowLocked = ui_task.isLocked();
|
||||||
|
if (nowLocked && !wasLocked) {
|
||||||
|
cpuPower.setLowPower();
|
||||||
|
Serial.printf("[Power] Low-power mode: CPU %d MHz, loop throttled\n",
|
||||||
|
cpuPower.getFrequencyMHz());
|
||||||
|
} else if (!nowLocked && wasLocked) {
|
||||||
|
cpuPower.clearLowPower();
|
||||||
|
Serial.printf("[Power] Normal mode: CPU %d MHz\n",
|
||||||
|
cpuPower.getFrequencyMHz());
|
||||||
|
}
|
||||||
|
wasLocked = nowLocked;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// Audiobook: service audio decode regardless of which screen is active
|
// Audiobook: service audio decode regardless of which screen is active
|
||||||
#if defined(LilyGo_TDeck_Pro) && !defined(HAS_4G_MODEM)
|
#if defined(LilyGo_TDeck_Pro) && !defined(HAS_4G_MODEM)
|
||||||
{
|
{
|
||||||
@@ -2182,6 +2203,16 @@ void loop() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Low-power loop throttle — yield CPU when lock screen is active.
|
||||||
|
// The RTOS idle task executes WFI (wait-for-interrupt) during delay(),
|
||||||
|
// dramatically reducing CPU power draw. 50 ms gives 20 loop cycles/sec
|
||||||
|
// which is ample for LoRa packet reception (radio has hardware FIFO).
|
||||||
|
#if defined(LilyGo_T5S3_EPaper_Pro) || defined(LilyGo_TDeck_Pro)
|
||||||
|
if (ui_task.isLocked()) {
|
||||||
|
delay(50);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|||||||
@@ -1844,7 +1844,7 @@ void UITask::lockScreen() {
|
|||||||
_next_refresh = 0; // Draw lock screen immediately
|
_next_refresh = 0; // Draw lock screen immediately
|
||||||
_auto_off = millis() + 60000; // 60s before display off while locked
|
_auto_off = millis() + 60000; // 60s before display off while locked
|
||||||
_lastLockRefresh = millis(); // Start 15-min clock refresh cycle
|
_lastLockRefresh = millis(); // Start 15-min clock refresh cycle
|
||||||
Serial.println("[UI] Screen locked");
|
Serial.println("[UI] Screen locked — entering low-power mode");
|
||||||
}
|
}
|
||||||
|
|
||||||
void UITask::unlockScreen() {
|
void UITask::unlockScreen() {
|
||||||
@@ -1863,7 +1863,7 @@ void UITask::unlockScreen() {
|
|||||||
_auto_off = millis() + AUTO_OFF_MILLIS;
|
_auto_off = millis() + AUTO_OFF_MILLIS;
|
||||||
_lastInputMillis = millis(); // Reset auto-lock idle timer
|
_lastInputMillis = millis(); // Reset auto-lock idle timer
|
||||||
_next_refresh = 0;
|
_next_refresh = 0;
|
||||||
Serial.println("[UI] Screen unlocked");
|
Serial.println("[UI] Screen unlocked — exiting low-power mode");
|
||||||
}
|
}
|
||||||
#endif // LilyGo_T5S3_EPaper_Pro || LilyGo_TDeck_Pro
|
#endif // LilyGo_T5S3_EPaper_Pro || LilyGo_TDeck_Pro
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ def merge_bin(source, target, env):
|
|||||||
bootloader = os.path.join(build_dir, "bootloader.bin")
|
bootloader = os.path.join(build_dir, "bootloader.bin")
|
||||||
partitions = os.path.join(build_dir, "partitions.bin")
|
partitions = os.path.join(build_dir, "partitions.bin")
|
||||||
firmware = os.path.join(build_dir, "firmware.bin")
|
firmware = os.path.join(build_dir, "firmware.bin")
|
||||||
output = os.path.join(build_dir, "firmware_merged.bin")
|
output = os.path.join(build_dir, "firmware-merged.bin")
|
||||||
|
|
||||||
# Verify all inputs exist
|
# Verify all inputs exist
|
||||||
for f in [bootloader, partitions, firmware]:
|
for f in [bootloader, partitions, firmware]:
|
||||||
|
|||||||
BIN
readback.bin
Normal file
BIN
readback.bin
Normal file
Binary file not shown.
@@ -8,9 +8,10 @@
|
|||||||
// 240 MHz ~70-80 mA
|
// 240 MHz ~70-80 mA
|
||||||
// 160 MHz ~50-60 mA
|
// 160 MHz ~50-60 mA
|
||||||
// 80 MHz ~30-40 mA
|
// 80 MHz ~30-40 mA
|
||||||
|
// 40 MHz ~15-20 mA (low-power / lock screen mode)
|
||||||
//
|
//
|
||||||
// SPI peripherals and UART use their own clock dividers from the APB clock,
|
// SPI peripherals and UART use their own clock dividers from the APB clock,
|
||||||
// so LoRa, e-ink, and GPS serial all work fine at 80MHz.
|
// so LoRa, e-ink, and GPS serial all work fine at 80MHz and 40MHz.
|
||||||
|
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
|
|
||||||
@@ -22,23 +23,36 @@
|
|||||||
#define CPU_FREQ_BOOST 240 // MHz — heavy processing
|
#define CPU_FREQ_BOOST 240 // MHz — heavy processing
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef CPU_FREQ_LOW_POWER
|
||||||
|
#define CPU_FREQ_LOW_POWER 40 // MHz — lock screen / idle standby
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef CPU_BOOST_TIMEOUT_MS
|
#ifndef CPU_BOOST_TIMEOUT_MS
|
||||||
#define CPU_BOOST_TIMEOUT_MS 10000 // 10 seconds
|
#define CPU_BOOST_TIMEOUT_MS 10000 // 10 seconds
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
class CPUPowerManager {
|
class CPUPowerManager {
|
||||||
public:
|
public:
|
||||||
CPUPowerManager() : _boosted(false), _boost_started(0) {}
|
CPUPowerManager() : _boosted(false), _lowPower(false), _boost_started(0) {}
|
||||||
|
|
||||||
void begin() {
|
void begin() {
|
||||||
setCpuFrequencyMhz(CPU_FREQ_IDLE);
|
setCpuFrequencyMhz(CPU_FREQ_IDLE);
|
||||||
_boosted = false;
|
_boosted = false;
|
||||||
|
_lowPower = false;
|
||||||
MESH_DEBUG_PRINTLN("CPU power: idle at %d MHz", CPU_FREQ_IDLE);
|
MESH_DEBUG_PRINTLN("CPU power: idle at %d MHz", CPU_FREQ_IDLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
if (_boosted && (millis() - _boost_started >= CPU_BOOST_TIMEOUT_MS)) {
|
if (_boosted && (millis() - _boost_started >= CPU_BOOST_TIMEOUT_MS)) {
|
||||||
setIdle();
|
// Return to low-power if locked, otherwise normal idle
|
||||||
|
if (_lowPower) {
|
||||||
|
setCpuFrequencyMhz(CPU_FREQ_LOW_POWER);
|
||||||
|
MESH_DEBUG_PRINTLN("CPU power: boost expired, returning to low-power %d MHz", CPU_FREQ_LOW_POWER);
|
||||||
|
} else {
|
||||||
|
setCpuFrequencyMhz(CPU_FREQ_IDLE);
|
||||||
|
MESH_DEBUG_PRINTLN("CPU power: idle at %d MHz", CPU_FREQ_IDLE);
|
||||||
|
}
|
||||||
|
_boosted = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,13 +71,42 @@ public:
|
|||||||
_boosted = false;
|
_boosted = false;
|
||||||
MESH_DEBUG_PRINTLN("CPU power: idle at %d MHz", CPU_FREQ_IDLE);
|
MESH_DEBUG_PRINTLN("CPU power: idle at %d MHz", CPU_FREQ_IDLE);
|
||||||
}
|
}
|
||||||
|
if (_lowPower) {
|
||||||
|
_lowPower = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Low-power mode — drops CPU to 40 MHz for lock screen standby.
|
||||||
|
// If currently boosted, the boost timeout will return to 40 MHz
|
||||||
|
// instead of 80 MHz.
|
||||||
|
void setLowPower() {
|
||||||
|
_lowPower = true;
|
||||||
|
if (!_boosted) {
|
||||||
|
setCpuFrequencyMhz(CPU_FREQ_LOW_POWER);
|
||||||
|
MESH_DEBUG_PRINTLN("CPU power: low-power at %d MHz", CPU_FREQ_LOW_POWER);
|
||||||
|
}
|
||||||
|
// If boosted, the loop() timeout will drop to low-power instead of idle
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit low-power mode — returns to normal idle (80 MHz).
|
||||||
|
// If currently boosted, the boost timeout will return to idle
|
||||||
|
// instead of low-power.
|
||||||
|
void clearLowPower() {
|
||||||
|
_lowPower = false;
|
||||||
|
if (!_boosted) {
|
||||||
|
setCpuFrequencyMhz(CPU_FREQ_IDLE);
|
||||||
|
MESH_DEBUG_PRINTLN("CPU power: idle at %d MHz (low-power cleared)", CPU_FREQ_IDLE);
|
||||||
|
}
|
||||||
|
// If boosted, the loop() timeout will drop to idle as normal
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isBoosted() const { return _boosted; }
|
bool isBoosted() const { return _boosted; }
|
||||||
|
bool isLowPower() const { return _lowPower; }
|
||||||
uint32_t getFrequencyMHz() const { return getCpuFrequencyMhz(); }
|
uint32_t getFrequencyMHz() const { return getCpuFrequencyMhz(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool _boosted;
|
bool _boosted;
|
||||||
|
bool _lowPower;
|
||||||
unsigned long _boost_started;
|
unsigned long _boost_started;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -8,9 +8,10 @@
|
|||||||
// 240 MHz ~70-80 mA
|
// 240 MHz ~70-80 mA
|
||||||
// 160 MHz ~50-60 mA
|
// 160 MHz ~50-60 mA
|
||||||
// 80 MHz ~30-40 mA
|
// 80 MHz ~30-40 mA
|
||||||
|
// 40 MHz ~15-20 mA (low-power / lock screen mode)
|
||||||
//
|
//
|
||||||
// SPI peripherals and UART use their own clock dividers from the APB clock,
|
// SPI peripherals and UART use their own clock dividers from the APB clock,
|
||||||
// so LoRa, e-ink, and GPS serial all work fine at 80MHz.
|
// so LoRa, e-ink, and GPS serial all work fine at 80MHz and 40MHz.
|
||||||
|
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
|
|
||||||
@@ -22,23 +23,36 @@
|
|||||||
#define CPU_FREQ_BOOST 240 // MHz — heavy processing
|
#define CPU_FREQ_BOOST 240 // MHz — heavy processing
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef CPU_FREQ_LOW_POWER
|
||||||
|
#define CPU_FREQ_LOW_POWER 40 // MHz — lock screen / idle standby
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef CPU_BOOST_TIMEOUT_MS
|
#ifndef CPU_BOOST_TIMEOUT_MS
|
||||||
#define CPU_BOOST_TIMEOUT_MS 10000 // 10 seconds
|
#define CPU_BOOST_TIMEOUT_MS 10000 // 10 seconds
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
class CPUPowerManager {
|
class CPUPowerManager {
|
||||||
public:
|
public:
|
||||||
CPUPowerManager() : _boosted(false), _boost_started(0) {}
|
CPUPowerManager() : _boosted(false), _lowPower(false), _boost_started(0) {}
|
||||||
|
|
||||||
void begin() {
|
void begin() {
|
||||||
setCpuFrequencyMhz(CPU_FREQ_IDLE);
|
setCpuFrequencyMhz(CPU_FREQ_IDLE);
|
||||||
_boosted = false;
|
_boosted = false;
|
||||||
|
_lowPower = false;
|
||||||
MESH_DEBUG_PRINTLN("CPU power: idle at %d MHz", CPU_FREQ_IDLE);
|
MESH_DEBUG_PRINTLN("CPU power: idle at %d MHz", CPU_FREQ_IDLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
if (_boosted && (millis() - _boost_started >= CPU_BOOST_TIMEOUT_MS)) {
|
if (_boosted && (millis() - _boost_started >= CPU_BOOST_TIMEOUT_MS)) {
|
||||||
setIdle();
|
// Return to low-power if locked, otherwise normal idle
|
||||||
|
if (_lowPower) {
|
||||||
|
setCpuFrequencyMhz(CPU_FREQ_LOW_POWER);
|
||||||
|
MESH_DEBUG_PRINTLN("CPU power: boost expired, returning to low-power %d MHz", CPU_FREQ_LOW_POWER);
|
||||||
|
} else {
|
||||||
|
setCpuFrequencyMhz(CPU_FREQ_IDLE);
|
||||||
|
MESH_DEBUG_PRINTLN("CPU power: idle at %d MHz", CPU_FREQ_IDLE);
|
||||||
|
}
|
||||||
|
_boosted = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,13 +71,42 @@ public:
|
|||||||
_boosted = false;
|
_boosted = false;
|
||||||
MESH_DEBUG_PRINTLN("CPU power: idle at %d MHz", CPU_FREQ_IDLE);
|
MESH_DEBUG_PRINTLN("CPU power: idle at %d MHz", CPU_FREQ_IDLE);
|
||||||
}
|
}
|
||||||
|
if (_lowPower) {
|
||||||
|
_lowPower = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Low-power mode — drops CPU to 40 MHz for lock screen standby.
|
||||||
|
// If currently boosted, the boost timeout will return to 40 MHz
|
||||||
|
// instead of 80 MHz.
|
||||||
|
void setLowPower() {
|
||||||
|
_lowPower = true;
|
||||||
|
if (!_boosted) {
|
||||||
|
setCpuFrequencyMhz(CPU_FREQ_LOW_POWER);
|
||||||
|
MESH_DEBUG_PRINTLN("CPU power: low-power at %d MHz", CPU_FREQ_LOW_POWER);
|
||||||
|
}
|
||||||
|
// If boosted, the loop() timeout will drop to low-power instead of idle
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit low-power mode — returns to normal idle (80 MHz).
|
||||||
|
// If currently boosted, the boost timeout will return to idle
|
||||||
|
// instead of low-power.
|
||||||
|
void clearLowPower() {
|
||||||
|
_lowPower = false;
|
||||||
|
if (!_boosted) {
|
||||||
|
setCpuFrequencyMhz(CPU_FREQ_IDLE);
|
||||||
|
MESH_DEBUG_PRINTLN("CPU power: idle at %d MHz (low-power cleared)", CPU_FREQ_IDLE);
|
||||||
|
}
|
||||||
|
// If boosted, the loop() timeout will drop to idle as normal
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isBoosted() const { return _boosted; }
|
bool isBoosted() const { return _boosted; }
|
||||||
|
bool isLowPower() const { return _lowPower; }
|
||||||
uint32_t getFrequencyMHz() const { return getCpuFrequencyMhz(); }
|
uint32_t getFrequencyMHz() const { return getCpuFrequencyMhz(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool _boosted;
|
bool _boosted;
|
||||||
|
bool _lowPower;
|
||||||
unsigned long _boost_started;
|
unsigned long _boost_started;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user