Skip to content

Commit 439b87b

Browse files
jp-bennettthebentern
authored andcommitted
Detach power interrupts for sleep (#10230)
* Detach power interrupts for sleep * Gate PMU IRQ behind a found PMU
1 parent d47301d commit 439b87b

3 files changed

Lines changed: 121 additions & 37 deletions

File tree

src/Power.cpp

Lines changed: 99 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -717,37 +717,17 @@ bool Power::setup()
717717
found = true;
718718
#endif
719719
}
720-
#ifdef EXT_PWR_DETECT
721-
attachInterrupt(
722-
EXT_PWR_DETECT,
723-
[]() {
724-
power->setIntervalFromNow(0);
725-
runASAP = true;
726-
},
727-
CHANGE);
728-
#endif
729-
#ifdef BATTERY_CHARGING_INV
730-
attachInterrupt(
731-
BATTERY_CHARGING_INV,
732-
[]() {
733-
power->setIntervalFromNow(0);
734-
runASAP = true;
735-
},
736-
CHANGE);
737-
#endif
738-
#ifdef EXT_CHRG_DETECT
739-
attachInterrupt(
740-
EXT_CHRG_DETECT,
741-
[]() {
742-
power->setIntervalFromNow(0);
743-
runASAP = true;
744-
BaseType_t higherWake = 0;
745-
},
746-
CHANGE);
747-
#endif
720+
attachPowerInterrupts();
748721
enabled = found;
749722
low_voltage_counter = 0;
750723

724+
#ifdef ARCH_ESP32
725+
// Register callbacks for before and after lightsleep
726+
// Used to detach and reattach interrupts
727+
lsObserver.observe(&notifyLightSleep);
728+
lsEndObserver.observe(&notifyLightSleepEnd);
729+
#endif
730+
751731
return found;
752732
}
753733

@@ -1026,6 +1006,97 @@ int32_t Power::runOnce()
10261006
return (statusHandler && statusHandler->isInitialized()) ? (1000 * 20) : RUN_SAME;
10271007
}
10281008

1009+
#ifdef ARCH_ESP32
1010+
1011+
// Detach our class' interrupts before lightsleep
1012+
// Allows sleep.cpp to configure its own interrupts, which wake the device on user-button press
1013+
int Power::beforeLightSleep(void *unused)
1014+
{
1015+
LOG_WARN("Detaching power interrupts for sleep");
1016+
detachPowerInterrupts();
1017+
return 0; // Indicates success
1018+
}
1019+
1020+
// Reconfigure our interrupts
1021+
// Our class' interrupts were disconnected during sleep, to allow the user button to wake the device from sleep
1022+
int Power::afterLightSleep(esp_sleep_wakeup_cause_t cause)
1023+
{
1024+
attachPowerInterrupts();
1025+
return 0; // Indicates success
1026+
}
1027+
1028+
#endif
1029+
1030+
/*
1031+
* Attach (or re-attach) hardware interrupts for power management
1032+
* Public method. Used outside class when waking from MCU sleep
1033+
*/
1034+
void Power::attachPowerInterrupts()
1035+
{
1036+
#ifdef EXT_PWR_DETECT
1037+
attachInterrupt(
1038+
EXT_PWR_DETECT,
1039+
[]() {
1040+
power->setIntervalFromNow(0);
1041+
runASAP = true;
1042+
},
1043+
CHANGE);
1044+
#endif
1045+
#ifdef BATTERY_CHARGING_INV
1046+
attachInterrupt(
1047+
BATTERY_CHARGING_INV,
1048+
[]() {
1049+
power->setIntervalFromNow(0);
1050+
runASAP = true;
1051+
},
1052+
CHANGE);
1053+
#endif
1054+
#ifdef EXT_CHRG_DETECT
1055+
attachInterrupt(
1056+
EXT_CHRG_DETECT,
1057+
[]() {
1058+
power->setIntervalFromNow(0);
1059+
runASAP = true;
1060+
BaseType_t higherWake = 0;
1061+
},
1062+
CHANGE);
1063+
#endif
1064+
#ifdef PMU_IRQ
1065+
if (PMU) {
1066+
attachInterrupt(
1067+
PMU_IRQ,
1068+
[] {
1069+
pmu_irq = true;
1070+
power->setIntervalFromNow(0);
1071+
runASAP = true;
1072+
},
1073+
FALLING);
1074+
}
1075+
#endif
1076+
}
1077+
1078+
/*
1079+
* Detach the "normal" button interrupts.
1080+
* Public method. Used before attaching a "wake-on-button" interrupt for MCU sleep
1081+
*/
1082+
void Power::detachPowerInterrupts()
1083+
{
1084+
#ifdef EXT_PWR_DETECT
1085+
detachInterrupt(EXT_PWR_DETECT);
1086+
#endif
1087+
#ifdef BATTERY_CHARGING_INV
1088+
detachInterrupt(BATTERY_CHARGING_INV);
1089+
#endif
1090+
#ifdef EXT_CHRG_DETECT
1091+
detachInterrupt(EXT_CHRG_DETECT);
1092+
#endif
1093+
#ifdef PMU_IRQ
1094+
if (PMU) {
1095+
detachInterrupt(PMU_IRQ);
1096+
}
1097+
#endif
1098+
}
1099+
10291100
/**
10301101
* Init the power manager chip
10311102
*
@@ -1303,8 +1374,6 @@ bool Power::axpChipInit()
13031374
}
13041375

13051376
pinMode(PMU_IRQ, INPUT);
1306-
attachInterrupt(
1307-
PMU_IRQ, [] { pmu_irq = true; }, FALLING);
13081377

13091378
// we do not look for AXPXXX_CHARGING_FINISHED_IRQ & AXPXXX_CHARGING_IRQ
13101379
// because it occurs repeatedly while there is no battery also it could cause

src/power.h

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ extern RAK9154Sensor rak9154Sensor;
8181
extern XPowersLibInterface *PMU;
8282
#endif
8383

84-
class Power : private concurrency::OSThread
84+
class Power : public concurrency::OSThread
8585
{
8686

8787
public:
@@ -96,6 +96,14 @@ class Power : private concurrency::OSThread
9696
void setStatusHandler(meshtastic::PowerStatus *handler) { statusHandler = handler; }
9797
const uint16_t OCV[11] = {OCV_ARRAY};
9898

99+
#ifdef ARCH_ESP32
100+
int beforeLightSleep(void *unused);
101+
int afterLightSleep(esp_sleep_wakeup_cause_t cause);
102+
#endif
103+
104+
void attachPowerInterrupts();
105+
void detachPowerInterrupts();
106+
99107
protected:
100108
meshtastic::PowerStatus *statusHandler;
101109

@@ -120,6 +128,14 @@ class Power : private concurrency::OSThread
120128
// open circuit voltage lookup table
121129
uint8_t low_voltage_counter;
122130
uint32_t lastLogTime = 0;
131+
132+
#ifdef ARCH_ESP32
133+
// Get notified when lightsleep begins and ends
134+
CallbackObserver<Power, void *> lsObserver = CallbackObserver<Power, void *>(this, &Power::beforeLightSleep);
135+
CallbackObserver<Power, esp_sleep_wakeup_cause_t> lsEndObserver =
136+
CallbackObserver<Power, esp_sleep_wakeup_cause_t>(this, &Power::afterLightSleep);
137+
#endif
138+
123139
#ifdef DEBUG_HEAP
124140
uint32_t lastheap;
125141
#endif

src/sleep.cpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -497,13 +497,12 @@ esp_sleep_wakeup_cause_t doLightSleep(uint64_t sleepMsec) // FIXME, use a more r
497497
esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause();
498498
notifyLightSleepEnd.notifyObservers(cause); // Button interrupts are reattached here
499499

500-
#ifdef BUTTON_PIN
501500
if (cause == ESP_SLEEP_WAKEUP_GPIO) {
502-
LOG_INFO("Exit light sleep gpio: btn=%d",
503-
!digitalRead(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN));
504-
} else
505-
#endif
506-
{
501+
LOG_INFO("Exit light sleep gpio");
502+
// If we woke because of a GPIO, it's possible power needs to run to handle.
503+
power->setIntervalFromNow(0);
504+
runASAP = true;
505+
} else {
507506
LOG_INFO("Exit light sleep cause: %d", cause);
508507
}
509508

0 commit comments

Comments
 (0)