Skip to content

Commit 76a46a7

Browse files
authored
Merge pull request #1562 from oltaco/nrf52-sleep-repeater
Add Low-Power Sleep for nRF52 Boards
2 parents 4b9d546 + a342ab8 commit 76a46a7

3 files changed

Lines changed: 33 additions & 3 deletions

File tree

examples/simple_repeater/main.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -127,14 +127,17 @@ void loop() {
127127
#endif
128128
rtc_clock.tick();
129129

130-
if (the_mesh.getNodePrefs()->powersaving_enabled && // To check if power saving is enabled
131-
the_mesh.millisHasNowPassed(lastActive + nextSleepinSecs * 1000)) { // To check if it is time to sleep
132-
if (!the_mesh.hasPendingWork()) { // No pending work. Safe to sleep
130+
if (the_mesh.getNodePrefs()->powersaving_enabled && !the_mesh.hasPendingWork()) {
131+
#if defined(NRF52_PLATFORM)
132+
board.sleep(1800); // nrf ignores seconds param, sleeps whenever possible
133+
#else
134+
if (the_mesh.millisHasNowPassed(lastActive + nextSleepinSecs * 1000)) { // To check if it is time to sleep
133135
board.sleep(1800); // To sleep. Wake up after 30 minutes or when receiving a LoRa packet
134136
lastActive = millis();
135137
nextSleepinSecs = 5; // Default: To work for 5s and sleep again
136138
} else {
137139
nextSleepinSecs += 5; // When there is pending work, to work another 5s
138140
}
141+
#endif
139142
}
140143
}

src/helpers/NRF52Board.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,32 @@ void NRF52BoardDCDC::begin() {
251251
}
252252
}
253253

254+
void NRF52Board::sleep(uint32_t secs) {
255+
// Clear FPU interrupt flags to avoid insomnia
256+
// see errata 87 for details https://docs.nordicsemi.com/bundle/errata_nRF52840_Rev3/page/ERR/nRF52840/Rev3/latest/anomaly_840_87.html
257+
#if (__FPU_USED == 1)
258+
__set_FPSCR(__get_FPSCR() & ~(0x0000009F));
259+
(void) __get_FPSCR();
260+
NVIC_ClearPendingIRQ(FPU_IRQn);
261+
#endif
262+
263+
// On nRF52, we use event-driven sleep instead of timed sleep
264+
// The 'secs' parameter is ignored - we wake on any interrupt
265+
uint8_t sd_enabled = 0;
266+
sd_softdevice_is_enabled(&sd_enabled);
267+
268+
if (sd_enabled) {
269+
// first call processes pending softdevice events, second call sleeps.
270+
sd_app_evt_wait();
271+
sd_app_evt_wait();
272+
} else {
273+
// softdevice is disabled, use raw WFE
274+
__SEV();
275+
__WFE();
276+
__WFE();
277+
}
278+
}
279+
254280
// Temperature from NRF52 MCU
255281
float NRF52Board::getMCUTemperature() {
256282
NRF_TEMP->TASKS_START = 1; // Start temperature measurement

src/helpers/NRF52Board.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ class NRF52Board : public mesh::MainBoard {
5151
virtual float getMCUTemperature() override;
5252
virtual void reboot() override { NVIC_SystemReset(); }
5353
virtual bool startOTAUpdate(const char *id, char reply[]) override;
54+
virtual void sleep(uint32_t secs) override;
5455

5556
#ifdef NRF52_POWER_MANAGEMENT
5657
bool isExternalPowered() override;

0 commit comments

Comments
 (0)