-
Notifications
You must be signed in to change notification settings - Fork 395
NRF52 Repeater Powersaving #1238
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Conversation
|
I intended to do the same before. So I ended up just do some power saving trick to keep the power down to 8.5mA with few code changes only. Hope we can push the power down more for NRF52 |
Yes, there is no real sleep mode for NRF52 so either put the CPU in idle to save power or shut it down completely. The latter requires full reinit at wakeup.
In which case? With the MCU shut down and only the RF module running in RX mode? That would be in that ballpark, yes.
Sorry, I don't get what you mean here.
Actually it doesn't look complex to me at all. It's pretty straight forward. Instead of letting the CPU run continuously, it stops it and resumes it after the idle interval is over or a packet is received. What exactly looks complex to you?
What "trick" would that be? Do you mean And if it would work, it would do the same thing: put the CPU in idle, right? My approach does it in a platform-agnostic way, which is better IMHO. |
|
This feature has been long overdue. I tested it a bit with Heltec t114 (no screen) repeater. With stock FW I am seeing around 12 mA idle current on my cheap usb power meter. It is actually quite good - it used to be around 17 mA with stock FW not so long ago. Then I flashed FW from this branch and immediately went for "set idle.interval 10000". Now my cheapo usb meter shows current at 0 mA, which occasionally jumps briefly to 10 mA while idling. If I send a message from my companion then the repeater wakes, repeats and then goes back to idling. Now, the 0mA is probably just an artifact of my usb meter. I will try some additional tests tomorrow, but what I see so far - the power consumption at idle is noticeably lower and repeater still seems to be repeating messages and responding to admin commands etc What is the intended reasonable idle interval? Something like 1 to 3 seconds? |
|
May be I will add the CLI for esp32 based boards. Should we share the same CLI to enable/disable power saving to both esp32 and nrf52? Like set powersave 1? In your PR, you set the idle period? How about wake up period? |
|
@ngavars You have to measure the current at the battery cable by power meter. A usbc, it needs to turn on unneccessary components like uart chip, led... |
In my opinion we should use the same approach for ESP32 and NRF52 altogether. You should be able to take my generic implementation and simply add the
What would that be good for? A single parameter that sets the length of the sleep/idle interval is enough. If set to zero (default) there is no change compared to the current implementation in the main branch. Repeater admins can then decide if they want to save power by increasing the interval.
The idle interval is the time the CPU is idling/sleeping. The wake interval is hardcoded to five seconds or three minutes after reboot or after CLI activity. I don't think this needs to be a parameter for the user to change. |
The |
|
@ngavars Thanks for testing by the way! |
mtlynch
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm just a user sharing my thoughts and have no authority in this project.
Thanks for your review anyway! Very much appreciated! |
ba6e6aa to
1dfb6d7
Compare
|
I've had this running on my test repeater (RAK4630) for 3 days now and I can't see any negative or unexpected results. I currently do not have any ESP32 hardware to test, so if someone would be willing to help out that would be very much appreciated! 😃 |
1dfb6d7 to
37d0fe1
Compare
Can you attach/upload somewhere an bin file for v3 for testing? |
|
@SaschaKt You can find an archive with all repeater firmwares built by the GitHub CI here: https://github.com/fschrempf/MeshCore/actions/runs/20347701758/artifacts/4916433935 |
I flashed it. Sorry for feedback after a few seconds. for v3 the powersaving is not so efficient like Iotthinks solution. I'm measuring over Usb-C and the consumption goes down from 48mA to 39mA with your solution, with Iotthinks solution it goes down to 13mA measured over Usb-C. Measuring on battery input pins will be a few mA less. I don't think that the combination of both solutions will give more power saving because I think that Lightsleep at esp's with iotthink solution also reduce CPU activity |
|
@SaschaKt Thanks for testing! This is the expected behavior. This PR does not (yet) include the code for ESP32 sleep. And yes, the combination of both solutions won't give more power savings for ESP32 than #1107. The reason for my PR is that it provides a generic approach that is also applicable for other platforms than ESP32 while still providing the possibility to be extended by platform-specific sleep. If your test shows a slightly reduced power consumption and the repeater still works fine that's a success. |
It works, I could go normal to cli and start OTA and flash with Iotthink variant again. Now again 13mA. 39mA is still too much. nrF have per default enabled power saving internally and are at the small consumption level, with tweaking maybe a few mA savings. But esp's needs an enabled lightsleep to be useful as a repeater. The advantage of an nrF is that still with enabled BT the power consumption is not noticeable higher then without. Where is the problem to have two power routines, one for esp's and one for NRFs? Also Iotthink made powersavings for nrF too which will reduce from 12.5 to 8.5mA, that's about 32% |
@SaschaKt I think we are talking past each other. There is no problem here. What I want to achieve is a two step solution:
Apart from the differences mentioned in #1107 (review) this is purely a strategic difference from what #1107 does. |
You're right. I can confirm that with v3 the powerconsumption goes from 48mA to 39mA. That's an improvement..I hope that it would not interfere with hardware specific power saving ontop like iotthink has made..this has to be tested |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for working on this @fschrempf 👍 It would be good to see some more power saving for my Solar RAK19003 node :)
Having said that, I wonder if if would be better if the idle interval would be computed automatically rather than using a fixed duration. For example, in The Netherlands the mesh has grown exponentially. Where 2 months ago the mesh saw some activity, now I see hundreds of daily messages (let alone adverts) and (some parts of) Belgium and Germany have been connected. I wouldn't be surprised to see more of Germany and France starting to appear. An idle interval that worked a couple of weeks ago (maybe even days ago) may not work as well today.
Additionally, if CPU idling is triggered, how would one be able to enter remote management mode? IMHO when trying to use remote management or fetching telemetry, idling should be cancelled and the idle timer should be reset.
examples/simple_repeater/MyMesh.cpp
Outdated
| _prefs.advert_loc_policy = ADVERT_LOC_PREFS; | ||
|
|
||
| _prefs.adc_multiplier = 0.0f; // 0.0f means use default board multiplier | ||
| _prefs.idle_interval = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps add a comment to better explain what this means:
| _prefs.idle_interval = 0; | |
| // CPU Idle Interval (in seconds). | |
| // | |
| // If enabled (> 0), the CPU will start idling if there has not been any radio activity for | |
| // the specified number of seconds. | |
| // | |
| // Note: When the CPU is idling, remote management and / or UI will cease to function! | |
| _prefs.idle_interval = 0; |
Or shorter:
| _prefs.idle_interval = 0; | |
| _prefs.idle_interval = 0; // CPU will idle when no RF activity during this interval (in sec, 0 = disabled) |
It will wake up on any RX event. Remote management works nicely, at least in all my tests so far. |
@4np How is the idle interval related to the mesh activity? During idle the repeater will still respond to incoming packets. Only outgoing packets will be left waiting until the timeout expires. |
Thanks for the additional tests. This corresponds pretty nicely to the results of my own tests on RAK4631. |
|
@4np One more thing: Do you use any AI tools for you reviews and code snippets? If yes, please make sure that you will mention this in the future. I want to know when I'm dealing with feedback generated by a LLM. If this is not the case, just ignore my comment. Thanks! |
|
@fschrempf, actually, I wrote these. The one with the bullet points I wrote, but I did ask ChatGPT to rewrite what I wrote and summarize it more consistently.
It could indeed very well be that the many timers was the cause of the unresponsiveness. Good to hear you have good results :) I'll give the new firmware build a go. |
|
@4np Thanks for clarifying! |
|
@fschrempf I am sorry to report that my RAK19007 / RAK4631 is again unresponsive so it looks like your latest changes did not solve the issue. Battery was at 99% when I flashed the firmware yesterday evening, this morning it's again unresponsive. |
|
@4np Thanks for testing! That's strange. On my end with the old version the problem occurred after a few hours or a day at the latest. With the new version the repeater has worked fine for four days in a row now. I will try to do some further investigations. |
|
@fschrempf I applied a different implementation checking for
|
|
@fschrempf: So far so good, 19h uptime without stalls... It looks like sleeping when DIO1 is HIGH is the cause of the unresponsiveness. As this is related to SX126x, I wonder if the same deadlock may happen in the ESP32 implementation or if it's unique to NRF52?
The mesh here is pretty crowded and busy, maybe it's more quiet on your end? |
There is no reason to not use the reset pin as the RAK4630/31 module has it connected internally. Signed-off-by: Frieder Schrempf <frieder@fris.de>
This makes the code easier to read and allows for easier changing of the hardcoded values. Signed-off-by: Frieder Schrempf <frieder@fris.de>
When a CLI command is issued through the serial interface, extend the timeout for going to sleep to give the user more time for issuing more commands. Signed-off-by: Frieder Schrempf <frieder@fris.de>
This can be used to prevent sleeping during critical tasks like OTA update. Signed-off-by: Frieder Schrempf <frieder@fris.de>
In order to not interrupt the OTA update, prevent any sleep requests after the "start ota" command has been activated. Signed-off-by: Frieder Schrempf <frieder@fris.de>
If the radio driver state machine is not in receive mode, this means that processing of a packet is still in progress and we are not in an idle state. Signed-off-by: Frieder Schrempf <frieder@fris.de>
|
So I've been digging into the deadlock issue a bit more and got a pretty clear image of what is happening and how it can be prevented. 1.
|
a327007 to
ea99bc3
Compare
The ISR will be used for other purposes than just setting a flag, rename it accordingly. Signed-off-by: Frieder Schrempf <frieder@fris.de>
STATE_TX_WAIT is meant to be a single bit but is defined as two bits, therefore overlapping with STATE_RX. This causes incorrect results when the code uses the bits to handle the state machine. Fix this. Signed-off-by: Frieder Schrempf <frieder@fris.de>
In some cases it is useful to let the board driver know when the radio issues an RX interrupt. This can be used to wake up the board from a low power state asynchronously for example. Signed-off-by: Frieder Schrempf <frieder@fris.de>
ea99bc3 to
56213ca
Compare
|
I rebased the PR and implemented the following changes compared to the previous version:
I noticed that for some reason the serial debug messages on the USB CDC interface of the RAK4631 (using TinyUSB library) stop after the the first suspend/resume cycle. I couldn't find the reason for this yet. If anyone got an idea or could check if they see the same problem that would be appreciated. Here is a link to the CI build: https://github.com/fschrempf/MeshCore/actions/runs/20933125598/artifacts/5103765633 @4np Sorry for proposing yet another solution. I would have been fine with adding the DIO1 == LOW check as a fix but after trying to understand the issue I think this still has the potential of locking up, although the probability is likely lower than without the check. |
|
@fschrempf sure no problem, I think your investigation makes sense. I'll give the new build a go and see how it behaves on my end. In any case, my repeater has been up for 1 day and 18 hours without locking up with the DIO1 changes. |
|
@fschrempf your CI build does not contain the RAK4631 repeater, it failed to build (as did the other NRF52 variants): |
This uses a FreeRTOS semaphore to block the main loop task and resume it on RX radio IRQ or timeout. Using the Arduino core functions suspendLoop() and resumeLoop() can lead to deadlocks which can only be avoided by disabling IRQs and possibly missing incoming packets. Signed-off-by: Frieder Schrempf <frieder@fris.de>
56213ca to
1ae1d7b
Compare
Oh dear! I didn't notice because the job status is green. And locally my build worked because I had modified my Arduino core manually some weeks ago when I was doing some experiments. Therefore my local Therefore I now reverted to the original solution (used in the very first version of this PR, sometimes the first ideas are the best ;)) using a FreeRTOS binary semaphore. This is equally good and simple and also a recommended solution in the FreeRTOS docs. Sorry for the additional noise. I updated the explanatory post above accordingly. Here are the latest binaries from the CI build: https://github.com/fschrempf/MeshCore/actions/runs/20971258478/artifacts/5118537314 |
|
I just flashed |
|
@4np Ok, but don't spend too much efforts in testing. Currently it looks like we will go for @IoTThinks alternative solution in #1353. |
|
Maybe I should test #1353 instead then 😄 |
From 8mA to 4mA, very good, I'm using it from the first version primary with v3/v4 (48mA down to 9-10mA) as solar repeater |




In order to reduce the power consumption of NRF52 repeaters, this implements CPU idling by suspending the main task that runs the Arduino
loop().During the idle interval the CLI and the UI (if available) will be unresponsive. The RF module will be kept in RX mode and upon receiving a packet, the interrupt will cause the processing loop to continue immediately before going back to idle after all outgoing packets have been transferred.
On a RAK4631 repeater this can reduce the power consumption during RX mode from around 12 mA to around 7.5 mA.
Latest build artifacts from CI (updated 01/13/26): https://github.com/fschrempf/MeshCore/actions/runs/20971258478/artifacts/5118537314
Feedback, tests, reviews and questions welcome!