no need for LightSleep state on NRF52 CPUs

This commit is contained in:
geeksville 2020-04-24 11:21:10 -07:00
parent 7fa9d09d9f
commit bebaa838c4
3 changed files with 60 additions and 51 deletions

View File

@ -8,10 +8,10 @@ Minimum items needed to make sure hardware is good.
- DONE get old radio driver working on NRF52
- DONE basic test of BLE
- DONE get a debug 'serial' console working via the ICE passthrough feater
- Use the PMU driver
- Use the PMU driver on real hardware
- add a NEMA based GPS driver to test GPS
- Use new radio driver - possibly start with https://os.mbed.com/teams/Semtech/code/SX126xLib/
- Use UC1701 LCD driver. Still need to create at startup and probe on SPI
- Use new radio driver on real hardware - possibly start with https://os.mbed.com/teams/Semtech/code/SX126xLib/
- Use UC1701 LCD driver on real hardware. Still need to create at startup and probe on SPI
- test the LEDs
- test the buttons
- make a new boarddef with a variant.h file. Fix pins in that file. In particular (at least):
@ -35,14 +35,15 @@ Needed to be fully functional at least at the same level of the ESP32 boards. At
- turn on security for BLE, make pairing work
- make power management/sleep work properly
- make a settimeofday implementation
- make a file system implementation (preferably one that can see the files the bootloader also sees)
- make ble endpoints not require "start config", jsut have them start in config mode
- make a file system implementation (preferably one that can see the files the bootloader also sees) - use https://infocenter.nordicsemi.com/topic/com.nordic.infocenter.sdk5.v15.3.0/lib_fds_usage.html?cp=7_5_0_3_55_3
- make ble endpoints not require "start config", just have them start in config mode
- measure power management and confirm battery life
- use new PMU to provide battery voltage/% full to app (both bluetooth and screen)
- do initial power measurements
## Items to be 'feature complete'
- good power management tips: https://devzone.nordicsemi.com/nordic/nordic-blog/b/blog/posts/optimizing-power-on-nrf52-designs
- call PMU set_ADC_CONV(0) during sleep, to stop reading PMU adcs and decrease current draw
- do final power measurements
- backport the common PMU API between AXP192 and PmuBQ25703A
@ -55,13 +56,17 @@ Needed to be fully functional at least at the same level of the ESP32 boards. At
Nice ideas worth considering someday...
- Use NRF logger module (includes flash logging etc...) instead of DEBUG_MSG
- Use "LED softblink" library on NRF52 to do nice pretty "breathing" LEDs. Don't whack LED from main thread anymore.
- decrease BLE xmit power "At 0dBm with the DC/DC on, the nRF52832 transmitter draws 5.3mA. Increasing the TX power to +4dBm adds only 2.2mA. Decreasing it to -40 dBm saves only 2.6mA."
- in addition to the main CPU watchdog, use the PMU watchdog as a really big emergency hammer
- turn on 'shipping mode' in the PMU when device is 'off' - to cut battery draw to essentially zero
- make Lorro_BQ25703A read/write operations atomic, current version could let other threads sneak in (once we start using threads)
- turn on DFU assistance in the appload using the nordic DFU helper lib call
- make the segger logbuffer larger, move it to RAM that is preserved across reboots and support reading it out at runtime (to allow full log messages to be included in crash reports). Share this code with ESP32
- make the segger logbuffer larger, move it to RAM that is preserved across reboots and support reading it out at runtime (to allow full log messages to be included in crash reports). Share this code with ESP32 (use gcc noinit attribute)
- convert hardfaults/panics/asserts/wd exceptions into fault codes sent to phone
- stop enumerating all i2c devices at boot, it wastes power & time
- consider using "SYSTEMOFF" deep sleep mode, without RAM retension. Only useful for 'truly off - wake only by button press' only saves 1.5uA vs SYSTEMON. (SYSTEMON only costs 1.5uA). Possibly put PMU into shipping mode?
```
/*

View File

@ -10,28 +10,29 @@ Since one of the main goals of this project is long battery life, it is importan
From lower to higher power consumption.
* Super-deep-sleep (SDS) - everything is off, CPU, radio, bluetooth, GPS. Only wakes due to timer or button press. We enter this mode only after no radio comms for a few hours, used to put the device into what is effectively "off" mode.
- Super-deep-sleep (SDS) - everything is off, CPU, radio, bluetooth, GPS. Only wakes due to timer or button press. We enter this mode only after no radio comms for a few hours, used to put the device into what is effectively "off" mode.
onEntry: setBluetoothOn(false), call doDeepSleep
onExit: (standard bootup code, starts in DARK)
* deep-sleep (DS) - CPU is off, radio is on, bluetooth and GPS is off. Note: This mode is never used currently, because it only saves 1.5mA vs light-sleep
- deep-sleep (DS) - CPU is off, radio is on, bluetooth and GPS is off. Note: This mode is never used currently, because it only saves 1.5mA vs light-sleep
(Not currently used)
* light-sleep (LS) - CPU is suspended (RAM stays alive), radio is on, bluetooth is off, GPS is off. Note: currently GPS is not turned
- light-sleep (LS) - CPU is suspended (RAM stays alive), radio is on, bluetooth is off, GPS is off. Note: currently GPS is not turned
off during light sleep, but there is a TODO item to fix this.
NOTE: On NRF52 platforms (because CPU current draw is so low), light-sleep state is never used.
onEntry: setBluetoothOn(false), setGPSPower(false), doLightSleep()
onIdle: (if we wake because our led blink timer has expired) blink the led then go back to sleep until we sleep for ls_secs
onExit: setGPSPower(true), start trying to get gps lock: gps.startLock(), once lock arrives service.sendPosition(BROADCAST)
* No bluetooth (NB) - CPU is running, radio is on, GPS is on but bluetooth is off, screen is off.
- No bluetooth (NB) - CPU is running, radio is on, GPS is on but bluetooth is off, screen is off.
onEntry: setBluetoothOn(false)
onExit:
* running dark (DARK) - Everything is on except screen
- running dark (DARK) - Everything is on except screen
onEntry: setBluetoothOn(true)
onExit:
* full on (ON) - Everything is on
- full on (ON) - Everything is on
onEntry: setBluetoothOn(true), screen.setOn(true)
onExit: screen.setOn(false)
@ -39,27 +40,27 @@ off during light sleep, but there is a TODO item to fix this.
### events that increase CPU activity
* At cold boot: The initial state (after setup() has run) is DARK
* While in DARK: if we receive EVENT_BOOT, transition to ON (and show the bootscreen). This event will be sent if we detect we woke due to reset (as opposed to deep sleep)
* While in LS: Once every position_broadcast_secs (default 15 mins) - the unit will wake into DARK mode and broadcast a "networkPing" (our position) and stay alive for wait_bluetooth_secs (default 30 seconds). This allows other nodes to have a record of our last known position if we go away and allows a paired phone to hear from us and download messages.
* While in LS: Every send_owner_interval (defaults to 4, i.e. one hour), when we wake to send our position we _also_ broadcast our owner. This lets new nodes on the network find out about us or correct duplicate node number assignments.
* While in LS/NB/DARK: If the user presses a button (EVENT_PRESS) we go to full ON mode for screen_on_secs (default 30 seconds). Multiple presses keeps resetting this timeout
* While in LS/NB/DARK: If we receive new text messages (EVENT_RECEIVED_TEXT_MSG), we go to full ON mode for screen_on_secs (same as if user pressed a button)
* While in LS: while we receive packets on the radio (EVENT_RECEIVED_PACKET) we will wake and handle them and stay awake in NB mode for min_wake_secs (default 10 seconds)
* While in NB: If we do have packets the phone (EVENT_PACKETS_FOR_PHONE) would want we transition to DARK mode for wait_bluetooth secs.
* While in DARK/ON: If we receive EVENT_BLUETOOTH_PAIR we transition to ON and start our screen_on_secs timeout
* While in NB/DARK/ON: If we receive EVENT_NODEDB_UPDATED we transition to ON (so the new screen can be shown)
* While in DARK: While the phone talks to us over BLE (EVENT_CONTACT_FROM_PHONE) reset any sleep timers and stay in DARK (needed for bluetooth sw update and nice user experience if the user is reading/replying to texts)
- At cold boot: The initial state (after setup() has run) is DARK
- While in DARK: if we receive EVENT_BOOT, transition to ON (and show the bootscreen). This event will be sent if we detect we woke due to reset (as opposed to deep sleep)
- While in LS: Once every position_broadcast_secs (default 15 mins) - the unit will wake into DARK mode and broadcast a "networkPing" (our position) and stay alive for wait_bluetooth_secs (default 30 seconds). This allows other nodes to have a record of our last known position if we go away and allows a paired phone to hear from us and download messages.
- While in LS: Every send*owner_interval (defaults to 4, i.e. one hour), when we wake to send our position we \_also* broadcast our owner. This lets new nodes on the network find out about us or correct duplicate node number assignments.
- While in LS/NB/DARK: If the user presses a button (EVENT_PRESS) we go to full ON mode for screen_on_secs (default 30 seconds). Multiple presses keeps resetting this timeout
- While in LS/NB/DARK: If we receive new text messages (EVENT_RECEIVED_TEXT_MSG), we go to full ON mode for screen_on_secs (same as if user pressed a button)
- While in LS: while we receive packets on the radio (EVENT_RECEIVED_PACKET) we will wake and handle them and stay awake in NB mode for min_wake_secs (default 10 seconds)
- While in NB: If we do have packets the phone (EVENT_PACKETS_FOR_PHONE) would want we transition to DARK mode for wait_bluetooth secs.
- While in DARK/ON: If we receive EVENT_BLUETOOTH_PAIR we transition to ON and start our screen_on_secs timeout
- While in NB/DARK/ON: If we receive EVENT_NODEDB_UPDATED we transition to ON (so the new screen can be shown)
- While in DARK: While the phone talks to us over BLE (EVENT_CONTACT_FROM_PHONE) reset any sleep timers and stay in DARK (needed for bluetooth sw update and nice user experience if the user is reading/replying to texts)
### events that decrease cpu activity
* While in ON: If PRESS event occurs, reset screen_on_secs timer and tell the screen to handle the pess
* While in ON: If it has been more than screen_on_secs since a press, lower to DARK
* While in DARK: If time since last contact by our phone exceeds phone_timeout_secs (15 minutes), we transition down into NB mode
* While in DARK or NB: If nothing above is forcing us to stay in a higher mode (wait_bluetooth_secs, min_wake_secs) we will lower down to LS state
* While in LS: If either phone_sds_timeout_secs (default 2 hr) or mesh_sds_timeout_secs (default 2 hr) are exceeded we will lower into SDS mode for sds_secs (default 1 yr) (or a button press). (Note: phone_sds_timeout_secs is currently disabled for now, because most users
- While in ON: If PRESS event occurs, reset screen_on_secs timer and tell the screen to handle the pess
- While in ON: If it has been more than screen_on_secs since a press, lower to DARK
- While in DARK: If time since last contact by our phone exceeds phone_timeout_secs (15 minutes), we transition down into NB mode
- While in DARK or NB: If nothing above is forcing us to stay in a higher mode (wait_bluetooth_secs, min_wake_secs) we will lower down to LS state
- While in LS: If either phone_sds_timeout_secs (default 2 hr) or mesh_sds_timeout_secs (default 2 hr) are exceeded we will lower into SDS mode for sds_secs (default 1 yr) (or a button press). (Note: phone_sds_timeout_secs is currently disabled for now, because most users
are using without a phone)
* Any time we enter LS mode: We stay in that until an interrupt, button press or other state transition. Every ls_secs (default 1 hr) and let the arduino loop() run one iteration (FIXME, not sure if we need this at all), and then immediately reenter lightsleep mode on the CPU.
- Any time we enter LS mode: We stay in that until an interrupt, button press or other state transition. Every ls_secs (default 1 hr) and let the arduino loop() run one iteration (FIXME, not sure if we need this at all), and then immediately reenter lightsleep mode on the CPU.
TODO: Eventually these scheduled intervals should be synchronized to the GPS clock, so that we can consider leaving the lora receiver off to save even more power.
TODO: In NB mode we should put cpu into light sleep any time we really aren't that busy (without declaring LS state) - i.e. we should leave GPS on etc...
@ -68,18 +69,18 @@ TODO: In NB mode we should put cpu into light sleep any time we really aren't th
General ideas to hit the power draws our spreadsheet predicts. Do the easy ones before beta, the last 15% can be done after 1.0.
* don't even power on the gps until someone else wants our position, just stay in lora deep sleep until press or rxpacket (except for once an hour updates)
* (possibly bad idea - better to have lora radio always listen - check spreadsheet) have every node wake at the same tick and do their position syncs then go back to deep sleep
* lower BT announce interval to save battery
* change to use RXcontinuous mode and config to drop packets with bad CRC (see section 6.4 of datasheet) - I think this is already the case
* have mesh service run in a thread that stays blocked until a packet arrives from the RF95
* platformio sdkconfig CONFIG_PM and turn on modem sleep mode
* keep cpu 100% in deepsleep until irq from radio wakes it. Then stay awake for 30 secs to attempt delivery to phone.
* use https://lastminuteengineers.com/esp32-sleep-modes-power-consumption/ association sleep pattern to save power - but see https://github.com/espressif/esp-idf/issues/2070 and https://esp32.com/viewtopic.php?f=13&t=12182 it seems with BLE on the 'easy' draw people are getting is 80mA
* stop using loop() instead use a job queue and let cpu sleep
* measure power consumption and calculate battery life assuming no deep sleep
* do lowest sleep level possible where BT still works during normal sleeping, make sure cpu stays in that mode unless lora rx packet happens, bt rx packet happens or button press happens
* optionally do lora messaging only during special scheduled intervals (unless nodes are told to go to low latency mode), then deep sleep except during those intervals - before implementing calculate what battery life would be with this feature
* see section 7.3 of https://cdn.sparkfun.com/assets/learn_tutorials/8/0/4/RFM95_96_97_98W.pdf and have hope radio wake only when a valid packet is received. Possibly even wake the ESP32 from deep sleep via GPIO.
* never enter deep sleep while connected to USB power (but still go to other low power modes)
* when main cpu is idle (in loop), turn cpu clock rate down and/or activate special sleep modes. We want almost everything shutdown until it gets an interrupt.
- don't even power on the gps until someone else wants our position, just stay in lora deep sleep until press or rxpacket (except for once an hour updates)
- (possibly bad idea - better to have lora radio always listen - check spreadsheet) have every node wake at the same tick and do their position syncs then go back to deep sleep
- lower BT announce interval to save battery
- change to use RXcontinuous mode and config to drop packets with bad CRC (see section 6.4 of datasheet) - I think this is already the case
- have mesh service run in a thread that stays blocked until a packet arrives from the RF95
- platformio sdkconfig CONFIG_PM and turn on modem sleep mode
- keep cpu 100% in deepsleep until irq from radio wakes it. Then stay awake for 30 secs to attempt delivery to phone.
- use https://lastminuteengineers.com/esp32-sleep-modes-power-consumption/ association sleep pattern to save power - but see https://github.com/espressif/esp-idf/issues/2070 and https://esp32.com/viewtopic.php?f=13&t=12182 it seems with BLE on the 'easy' draw people are getting is 80mA
- stop using loop() instead use a job queue and let cpu sleep
- measure power consumption and calculate battery life assuming no deep sleep
- do lowest sleep level possible where BT still works during normal sleeping, make sure cpu stays in that mode unless lora rx packet happens, bt rx packet happens or button press happens
- optionally do lora messaging only during special scheduled intervals (unless nodes are told to go to low latency mode), then deep sleep except during those intervals - before implementing calculate what battery life would be with this feature
- see section 7.3 of https://cdn.sparkfun.com/assets/learn_tutorials/8/0/4/RFM95_96_97_98W.pdf and have hope radio wake only when a valid packet is received. Possibly even wake the ESP32 from deep sleep via GPIO.
- never enter deep sleep while connected to USB power (but still go to other low power modes)
- when main cpu is idle (in loop), turn cpu clock rate down and/or activate special sleep modes. We want almost everything shutdown until it gets an interrupt.

View File

@ -173,10 +173,13 @@ void PowerFSM_setup()
powerFSM.add_timed_transition(&stateDARK, &stateNB, radioConfig.preferences.phone_timeout_secs * 1000, NULL, "Phone timeout");
#ifndef NRF52_SERIES
// We never enter light-sleep state on NRF52 (because the CPU uses so little power normally)
powerFSM.add_timed_transition(&stateNB, &stateLS, radioConfig.preferences.min_wake_secs * 1000, NULL, "Min wake timeout");
powerFSM.add_timed_transition(&stateDARK, &stateLS, radioConfig.preferences.wait_bluetooth_secs * 1000, NULL,
"Bluetooth timeout");
#endif
powerFSM.add_timed_transition(&stateLS, &stateSDS, radioConfig.preferences.mesh_sds_timeout_secs * 1000, NULL,
"mesh timeout");