Pārlūkot izejas kodu

nrf52: allow repeater to sleep when idle

taco 6 mēneši atpakaļ
vecāks
revīzija
a342ab8437

+ 6 - 3
examples/simple_repeater/main.cpp

@@ -127,14 +127,17 @@ void loop() {
 #endif
   rtc_clock.tick();
 
-  if (the_mesh.getNodePrefs()->powersaving_enabled &&                     // To check if power saving is enabled
-      the_mesh.millisHasNowPassed(lastActive + nextSleepinSecs * 1000)) { // To check if it is time to sleep
-    if (!the_mesh.hasPendingWork()) { // No pending work. Safe to sleep
+  if (the_mesh.getNodePrefs()->powersaving_enabled && !the_mesh.hasPendingWork()) {
+    #if defined(NRF52_PLATFORM)
+    board.sleep(1800); // nrf ignores seconds param, sleeps whenever possible
+    #else
+    if (the_mesh.millisHasNowPassed(lastActive + nextSleepinSecs * 1000)) { // To check if it is time to sleep
       board.sleep(1800);             // To sleep. Wake up after 30 minutes or when receiving a LoRa packet
       lastActive = millis();
       nextSleepinSecs = 5;  // Default: To work for 5s and sleep again
     } else {
       nextSleepinSecs += 5; // When there is pending work, to work another 5s
     }
+    #endif
   }
 }

+ 26 - 0
src/helpers/NRF52Board.cpp

@@ -251,6 +251,32 @@ void NRF52BoardDCDC::begin() {
   }
 }
 
+void NRF52Board::sleep(uint32_t secs) {
+  // Clear FPU interrupt flags to avoid insomnia
+  // see errata 87 for details https://docs.nordicsemi.com/bundle/errata_nRF52840_Rev3/page/ERR/nRF52840/Rev3/latest/anomaly_840_87.html
+  #if (__FPU_USED == 1)
+  __set_FPSCR(__get_FPSCR() & ~(0x0000009F)); 
+  (void) __get_FPSCR();
+  NVIC_ClearPendingIRQ(FPU_IRQn);
+  #endif
+
+  // On nRF52, we use event-driven sleep instead of timed sleep
+  // The 'secs' parameter is ignored - we wake on any interrupt
+  uint8_t sd_enabled = 0;
+  sd_softdevice_is_enabled(&sd_enabled);
+
+  if (sd_enabled) {
+    // first call processes pending softdevice events, second call sleeps.
+    sd_app_evt_wait();
+    sd_app_evt_wait();
+  } else {
+    // softdevice is disabled, use raw WFE
+    __SEV();
+    __WFE();
+    __WFE();
+  }
+}
+
 // Temperature from NRF52 MCU
 float NRF52Board::getMCUTemperature() {
   NRF_TEMP->TASKS_START = 1; // Start temperature measurement

+ 1 - 0
src/helpers/NRF52Board.h

@@ -51,6 +51,7 @@ public:
   virtual float getMCUTemperature() override;
   virtual void reboot() override { NVIC_SystemReset(); }
   virtual bool startOTAUpdate(const char *id, char reply[]) override;
+  virtual void sleep(uint32_t secs) override;
 
 #ifdef NRF52_POWER_MANAGEMENT
   bool isExternalPowered() override;