Skip to content

Commit d18f3f7

Browse files
viricfifieldt
andauthored
Allow deepsleep in rak4630 and make it restart well when power comes back (#7882)
* Make RAK4631 nodes power back on deep sleep The devices will hang if the VBAT goes under 1.7V (Brown-out reset) and they will never come back unless power supply goes completely off. This kills unattended nodes. Using the SystemOff the LPCOMP we can get the nodes back again when power comes back, even if VBAT goes under 1.7V, which moreover is more unlikely because the device is off. * Adding support for heltec t114 And moved particularities to variant.h * Remove old cpp comment that belongs to variant.h It was a leftover. * Trunk fix --------- Co-authored-by: Tom Fifield <[email protected]>
1 parent 6c09cf9 commit d18f3f7

File tree

5 files changed

+52
-11
lines changed

5 files changed

+52
-11
lines changed

src/Power.cpp

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ static HasBatteryLevel *batteryLevel; // Default to NULL for no battery level se
194194

195195
#ifdef BATTERY_PIN
196196

197-
static void adcEnable()
197+
void battery_adcEnable()
198198
{
199199
#ifdef ADC_CTRL // enable adc voltage divider when we need to read
200200
#ifdef ADC_USE_PULLUP
@@ -214,7 +214,7 @@ static void adcEnable()
214214
#endif
215215
}
216216

217-
static void adcDisable()
217+
static void battery_adcDisable()
218218
{
219219
#ifdef ADC_CTRL // disable adc voltage divider when we need to read
220220
#ifdef ADC_USE_PULLUP
@@ -320,7 +320,7 @@ class AnalogBatteryLevel : public HasBatteryLevel
320320
uint32_t raw = 0;
321321
float scaled = 0;
322322

323-
adcEnable();
323+
battery_adcEnable();
324324
#ifdef ARCH_ESP32 // ADC block for espressif platforms
325325
raw = espAdcRead();
326326
scaled = esp_adc_cal_raw_to_voltage(raw, adc_characs);
@@ -332,7 +332,7 @@ class AnalogBatteryLevel : public HasBatteryLevel
332332
raw = raw / BATTERY_SENSE_SAMPLES;
333333
scaled = operativeAdcMultiplier * ((1000 * AREF_VOLTAGE) / pow(2, BATTERY_SENSE_RESOLUTION_BITS)) * raw;
334334
#endif
335-
adcDisable();
335+
battery_adcDisable();
336336

337337
if (!initial_read_done) {
338338
// Flush the smoothing filter with an ADC reading, if the reading is plausibly correct
@@ -906,13 +906,8 @@ void Power::readPowerStatus()
906906
low_voltage_counter++;
907907
LOG_DEBUG("Low voltage counter: %d/10", low_voltage_counter);
908908
if (low_voltage_counter > 10) {
909-
#ifdef ARCH_NRF52
910-
// We can't trigger deep sleep on NRF52, it's freezing the board
911-
LOG_DEBUG("Low voltage detected, but not trigger deep sleep");
912-
#else
913909
LOG_INFO("Low voltage detected, trigger deep sleep");
914910
powerFSM.trigger(EVENT_LOW_BATTERY);
915-
#endif
916911
}
917912
} else {
918913
low_voltage_counter = 0;
@@ -1552,4 +1547,4 @@ bool Power::meshSolarInit()
15521547
{
15531548
return false;
15541549
}
1555-
#endif
1550+
#endif

src/platform/nrf52/main-nrf52.cpp

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
#include "error.h"
1515
#include "main.h"
1616
#include "meshUtils.h"
17+
#include "power.h"
18+
19+
#include <hal/nrf_lpcomp.h>
1720

1821
#ifdef BQ25703A_ADDR
1922
#include "BQ25713.h"
@@ -389,6 +392,23 @@ void cpuDeepSleep(uint32_t msecToWake)
389392
nrf_gpio_cfg_sense_set(BUTTON_PIN, sense); // Apply SENSE to wake up the device from the deep sleep
390393
#endif
391394

395+
#ifdef BATTERY_LPCOMP_INPUT
396+
// Wake up if power rises again
397+
nrf_lpcomp_config_t c;
398+
c.reference = BATTERY_LPCOMP_THRESHOLD;
399+
c.detection = NRF_LPCOMP_DETECT_UP;
400+
c.hyst = NRF_LPCOMP_HYST_NOHYST;
401+
nrf_lpcomp_configure(NRF_LPCOMP, &c);
402+
nrf_lpcomp_input_select(NRF_LPCOMP, BATTERY_LPCOMP_INPUT);
403+
nrf_lpcomp_enable(NRF_LPCOMP);
404+
405+
battery_adcEnable();
406+
407+
nrf_lpcomp_task_trigger(NRF_LPCOMP, NRF_LPCOMP_TASK_START);
408+
while (!nrf_lpcomp_event_check(NRF_LPCOMP, NRF_LPCOMP_EVENT_READY))
409+
;
410+
#endif
411+
392412
auto ok = sd_power_system_off();
393413
if (ok != NRF_SUCCESS) {
394414
LOG_ERROR("FIXME: Ignoring soft device (EasyDMA pending?) and forcing system-off!");
@@ -420,4 +440,4 @@ void enterDfuMode()
420440
#else
421441
enterUf2Dfu();
422442
#endif
423-
}
443+
}

src/power.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,4 +144,6 @@ class Power : private concurrency::OSThread
144144
#endif
145145
};
146146

147+
void battery_adcEnable();
148+
147149
extern Power *power;

variants/nrf52840/heltec_mesh_node_t114/variant.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,16 @@ No longer populated on PCB
210210
#define VBAT_AR_INTERNAL AR_INTERNAL_3_0
211211
#define ADC_MULTIPLIER (4.916F)
212212

213+
// rf52840 AIN2 = Pin 4
214+
#define BATTERY_LPCOMP_INPUT NRF_LPCOMP_INPUT_2
215+
216+
// We have AIN2 with a VBAT divider so AIN2 = VBAT * (100/490)
217+
// We have the device going deep sleep under 3.1V, which is AIN2 = 0.63V
218+
// So we can wake up when VBAT>=VDD is restored to 3.3V, where AIN2 = 0.67V
219+
// Ratio 0.67/3.3 = 0.20, so we can pick a bit higher, 2/8 VDD, which means
220+
// VBAT=4.04V
221+
#define BATTERY_LPCOMP_THRESHOLD NRF_LPCOMP_REF_SUPPLY_2_8
222+
213223
#define HAS_RTC 0
214224
#ifdef __cplusplus
215225
}

variants/nrf52840/rak4631/variant.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,20 @@ SO GPIO 39/TXEN MAY NOT BE DEFINED FOR SUCCESSFUL OPERATION OF THE SX1262 - TG
267267
#define VBAT_AR_INTERNAL AR_INTERNAL_3_0
268268
#define ADC_MULTIPLIER 1.73
269269

270+
// RAK4630 AIN0 = nrf52840 AIN3 = Pin 5
271+
#define BATTERY_LPCOMP_INPUT NRF_LPCOMP_INPUT_3
272+
273+
// We have AIN3 with a VBAT divider so AIN3 = VBAT * (1.5/2.5)
274+
// We have the device going deep sleep under 3.1V, which is AIN3 = 1.86V
275+
// So we can wake up when VBAT>=VDD is restored to 3.3V, where AIN3 = 1.98V
276+
// 1.98/3.3 = 6/10, but that's close to the VBAT divider, so we
277+
// pick 6/8VDD, which means VBAT=4.1V.
278+
// Reference:
279+
// VDD=3.3V AIN3=5/8*VDD=2.06V VBAT=1.66*AIN3=3.41V
280+
// VDD=3.3V AIN3=11/16*VDD=2.26V VBAT=1.66*AIN3=3.76V
281+
// VDD=3.3V AIN3=6/8*VDD=2.47V VBAT=1.66*AIN3=4.1V
282+
#define BATTERY_LPCOMP_THRESHOLD NRF_LPCOMP_REF_SUPPLY_11_16
283+
270284
#define HAS_RTC 1
271285

272286
#define HAS_ETHERNET 1

0 commit comments

Comments
 (0)