Battery, EPD, and SD support for m5paper

Also hide button hints
This commit is contained in:
Justin Mitchell
2026-06-08 12:47:43 -04:00
parent 7f01eab62e
commit 38ad4f9036
12 changed files with 112 additions and 21 deletions
+23
View File
@@ -192,7 +192,13 @@ HalGPIO::DeviceType detectDeviceTypeWithFingerprint() {
void HalGPIO::begin() {
inputMgr.begin();
#if !(defined(FREEINK_DEVICE_M5PAPER) && FREEINK_DEVICE_M5PAPER)
// Claim the shared SPI bus with the X4/X3 display+SD pins. On M5Paper the SDK's
// IT8951 driver and SDCardManager each bring up SPI from BoardConfig::ACTIVE
// pins; pre-claiming VSPI here would stick (SPIClass::begin early-returns if the
// bus is already started) and leave the SD card on the wrong pins.
SPI.begin(EPD_SCLK, SPI_MISO, EPD_MOSI, EPD_CS);
#endif
_deviceType = detectDeviceTypeWithFingerprint();
@@ -232,12 +238,29 @@ void HalGPIO::startDeepSleep() {
inputMgr.update();
}
// Arm the wakeup trigger *after* the button is released
#if SOC_PM_SUPPORT_EXT1_WAKEUP
// Xtensa (classic ESP32 / S3): GPIO deep-sleep wake is via RTC ext1.
esp_sleep_enable_ext1_wakeup(1ULL << InputManager::POWER_BUTTON_PIN, ESP_EXT1_WAKEUP_ALL_LOW);
#else
// RISC-V (C3): direct GPIO deep-sleep wakeup source.
esp_deep_sleep_enable_gpio_wakeup(1ULL << InputManager::POWER_BUTTON_PIN, ESP_GPIO_WAKEUP_GPIO_LOW);
#endif
// Enter Deep Sleep
esp_deep_sleep_start();
}
void HalGPIO::verifyPowerButtonWakeup(uint16_t requiredDurationMs, bool shortPressAllowed) {
if (BoardConfig::ACTIVE.input.power < 0) {
// No readable power-button input pin: can't verify a hold, so don't sleep.
return;
}
#if defined(FREEINK_DEVICE_M5PAPER) && FREEINK_DEVICE_M5PAPER
// M5Paper: power-on is a hardware latch and the "power button" is the rotary
// push (G38), shared with Confirm. A USB/flash cold boot is indistinguishable
// from an intentional power-on hold here, so skip the X4-style anti-accidental-
// wake check and always boot. G38 still serves as the deep-sleep wake source.
return;
#endif
if (shortPressAllowed) {
// Fast path - no duration check needed
return;
+11 -2
View File
@@ -18,7 +18,9 @@ void HalPowerManager::begin() {
Wire.setTimeOut(4);
_batteryUseI2C = true;
} else {
pinMode(BAT_GPIO0, INPUT);
// Battery ADC pin from the active board profile (X4: GPIO0, M5Paper: GPIO35),
// not a hardcoded X4 pin.
pinMode(BoardConfig::ACTIVE.batteryAdc, INPUT);
}
normalFreq = getCpuFrequencyMhz();
modeMutex = xSemaphoreCreateMutex();
@@ -76,8 +78,10 @@ void HalPowerManager::startDeepSleep(HalGPIO& gpio) const {
#endif
// Pre-sleep routines from the original firmware
#if !SOC_PM_SUPPORT_EXT1_WAKEUP // RISC-V (C3 / X4)
// GPIO13 is connected to battery latch MOSFET, we need to make sure it's low during sleep
// Note that this means the MCU will be completely powered off during sleep, including RTC
// (X4-specific: on classic ESP32/M5Paper GPIO13 is SD MISO, so this is skipped.)
constexpr gpio_num_t GPIO_SPIWP = GPIO_NUM_13;
gpio_set_direction(GPIO_SPIWP, GPIO_MODE_OUTPUT);
gpio_set_level(GPIO_SPIWP, 0);
@@ -90,6 +94,10 @@ void HalPowerManager::startDeepSleep(HalGPIO& gpio) const {
// power button is hard-wired to briefly provide power to the MCU, waking it up regardless of the wakeup source
// configuration
esp_deep_sleep_enable_gpio_wakeup(1ULL << InputManager::POWER_BUTTON_PIN, ESP_GPIO_WAKEUP_GPIO_LOW);
#else // Xtensa (classic ESP32 / S3): RTC ext1 GPIO wake
pinMode(InputManager::POWER_BUTTON_PIN, INPUT_PULLUP);
esp_sleep_enable_ext1_wakeup(1ULL << InputManager::POWER_BUTTON_PIN, ESP_EXT1_WAKEUP_ALL_LOW);
#endif
// Enter Deep Sleep
esp_deep_sleep_start();
}
@@ -121,7 +129,8 @@ uint16_t HalPowerManager::getBatteryPercentage() const {
_batteryLastPollMs = now;
return _batteryCachedPercent;
}
static const BatteryMonitor battery = BatteryMonitor(BAT_GPIO0);
// ADC pin from the active profile (X4 GPIO0 / M5Paper GPIO35); default 2:1 divider.
static const BatteryMonitor battery = BatteryMonitor(BoardConfig::ACTIVE.batteryAdc);
// smooth the battery %.
if (_batteryCachedPercent == 0) {
+8
View File
@@ -38,6 +38,13 @@ void IRAM_ATTR __wrap_panic_print_backtrace(const void* frame, int core) {
__real_panic_print_backtrace(frame, core);
return;
}
#if !__riscv
// RvExcFrame and the flat SP scan below are RISC-V-only (C3). On Xtensa
// (classic ESP32 / S3) the exception frame is XtExcFrame with windowed-register
// unwinding, so fall back to the default backtrace.
__real_panic_print_backtrace(frame, core);
return;
#else
for (size_t i = 0; i < MAX_PANIC_STACK_DEPTH; i++) {
panicStack[i].sp = 0;
}
@@ -65,6 +72,7 @@ void IRAM_ATTR __wrap_panic_print_backtrace(const void* frame, int core) {
}
__real_panic_print_backtrace(frame, core);
#endif // __riscv
}
}