Open pbecchi opened 6 years ago
Thanks @pbecchi for raising this issue and share your experience with the power consumption. You are right with your observation, I will throw a bit more detail where I could.
I have also wanted to test more with power consumption and write an tutorial for it. But we are too busy for now with the upcoming nrf52840, which we will need do low power, so we wait until it comes out to test with. This will serve as notes to ourself to improve it later.
Another way to reduce power is to go full event response aka callback and abandon the use of loop() with suspendLoop() call. ( I will take note myself for the tutorial, before I start to forget things)
Also you may want to tweak the ble radio timing/parameter such adv, connection interval etc ... the full list and its affect (current save) will come later when I tested them with the bench ( we may go as far as low power profile with pre-configured parameter for user). There may be more trick, but I kind of forget, will get back to this when we are done with the nrf52840 :D
@hathach Thanks for your replay!
To be more precise on my previous message:
I use your libraries on nrf52 DK and on Fanstel BT832 modules ....so the Cp2104 cannot be the reason for the abnormal UART drain.
The high mA start in the setup() function just after startAdv() call. I have added a 1 minute delay() after that call . When I have a Serial.begin call the consumption is 1.5 mA and after 30s 0.6 mA. Without Serial.begin my consumption is floating from 1.5 to 3.5 mA. This behaviour dont shows up with the nrf52 DK board.
Is suspendLoop() a way to not start the loop task? I cannot do this since my code is a sprinkler controller and I need to spend few millisecond per minute to do GPIO controls. I can manage to use a delay(500) in my loop() that hopefully can reduce consumption to around 100uA
I need anyhow to solve the Serial related power drain......can you help me on that?
Yes, suspendLoop() will put loop() task in suspend and prevent it to execute. If you need it, so just use it if you need it.
For the serial issue with power, currently I don't have any ideas why it behaves as such. I am quite sure to not print anything when debug=0. Although, I am too busy by now for upcoming nrf52840 to pull out nrf52dk to test this out. I am afraid you have to do it by yourself a little bit more until we release the nrf52840 board. Sorry since I only have 2 hands and 10 fingers :))
Thanks, I understand your problems..... I am also very interested to the nrf52840 , since I am getting my first bt840 end of this week! :-)
So I will try to solve this power drain problem by myself and ...I will let you know!!
thanks, please update here if you could find out anything. Low power is mostly software thing ( hw is often too obvious and spotted out soon enough). It needs a guideline and discipline to follow. Unfortunately, we haven't got the guideline yet ( just some above tips )
related to #51
I'd have one more data point on unexpected power consumption - FPU. On a custom design (but still using nRF52 Feather framework, since that's what I prototype on), I have attained great idle power consumption (<0.5mA). But only till the first float multiplication. I initially blamed ADC, since it was in the battery measurement code, but it really turned out to the the float multiplication, after which my draw was constantly over 6.5mA. Then I have found https://devzone.nordicsemi.com/f/nordic-q-a/23242/single-float-division-causing-7x-higher-current-draw and the reference to the errata 87, which includes a workaround. Perhaps this workaround (clearing the FPU pending IRQ) could be easily applied to the Feather codebase (I have since avoided float math, to a great effect on idle power).
superb !!! That is brilliant finding, we will note this and make sure including this in our soon-coming testing and tutorial.
Interestingly enough, there seems to be (ifdef-outed) stub of the workaround in the waitForEvent implementation, as I have just found (looking into why my waitForEvent doesn't really sleep either, while delay() does pretty well) 0.8.3, wiring.c
use delay for the sleep(), it is mentioned in my above comment. waitForEvent will probably be removed the next time we work on systematizing power stuff. Here is sum up when you call delay
For details: https://www.freertos.org/low-power-tickless-rtos.html
I am moving towards tickless, though I wonder about threading model of the platform. Posted question on that topic at the forum (though at the end of the day, I might go with a central worker thread driving the UX that might get all the wakeup/event sources re-posted into...).
Thanks.
@Nenik it is rather simple, ble and soc run on their on thread, most of callback run on a worker thread ( some needs signature changes to be called in worker). Give me a couple of days, I will answer it more details in the forum topic.
Looking forward to that. But I've just discovered the beauty of xTimerPendFunctionCallFromISR() :-) That gets me covered for most of my needs, since most of the other stuff will come on the timer thread too, thus allowing simple serialization of the events... Thanks!
But I've just discovered the beauty of xTimerPendFunctionCallFromISR()
Except that the timer stack is only 100B deep :-( That's like 2 stack frames on Cortex and when I tried something nontrivial (code wise, not execution-time wise, I know to keep things short in such a context) on the timer thread, I've got a stack overflow.
I know how to modify the FreeRTOS config underneath, which gets me back into the game, but a reasonable extension of the timer thread stack sounds cheaper (memory-wise) than rolling out another handler thread to forward timed things into. nRF52 has plenty of memory anyways, by Arduino standards...
try our ada_callback() and ada_callback_fromISR()
it is meant to use internally for deferred callbacks. But can be served as generic worker thread, I may rename it to make that clearer and easier to use for Arduino sketch later.
Though you need to be aware of which thread your code is running, shouldn't wait for an semaphore or event that triggered within callback thread, while you are there. Some callback (not all, we do that later) has an option to be invoked in callback thread or in the main ble thread. You can make use of that for adv threading. e.g https://github.com/adafruit/Adafruit_nRF52_Arduino/blob/develop/libraries/Bluefruit52Lib/src/BLEClientCharacteristic.h#L103
PS: for continue with threading, please post on the forum, or if you found any bugs/improvement, post it in separated issue. This one is for low power, Although they are somewhat related.
HAve a look to this post :https://devzone.nordicsemi.com/f/nordic-q-a/36649/custom-board-using-bt832-and-bt832x-power-drain-issue/146816#146816 It show very strange behaviour of delay(500) on fanstell BT 832 module, while it work as expected on BT832X.
Nordik PPK is a very useful tool to understand power drains!
@pbecchi that is interesting, indeed Nordic PPK is very handy for analyzing the current. I have one here as well :D
@hathach You mentioned last summer:
- delay() in your library is more than delay as you figure out, more like sleep() now. Since we implement freeRTOS tickless https://www.freertos.org/low-power-tickless-rtos.html Everytime delay() is invoke it will put mcu into decent sleep mode (waitForEvent() ) an only wake up a few ticks before the time of scheduled action. It is all handled under the hood, man we should call it sleep() :D . It is a feature point in our upcoming "coding guideline for low power" tutorial. However the longer you delay/sleep the lower responsiveness of the device.
But when I got between waitForEvent vs. a delay, I'm seeing my current go from about 70ua to over 400ua... my scope trace shows waitForEvent is waking up every ~1ms where as with delay it's about every 20us. Perhaps I misunderstood this. Any thoughts welcome. My code sample is below, with relevant stuff at the very bottom
Thanks for any feedback
`/*********************************************************************
This is an example for our nRF52 based Bluefruit LE modules
Pick one up today in the adafruit shop!
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
MIT license, check LICENSE for more information
All text above, and the splash screen below must be included in
any redistribution
*********************************************************************/
#include <bluefruit.h>
// Beacon uses the Manufacturer Specific Data field in the advertising
// packet, which means you must provide a valid Manufacturer ID. Update
// the field below to an appropriate value. For a list of valid IDs see:
// https://www.bluetooth.com/specifications/assigned-numbers/company-identifiers
// 0x004C is Apple (for example)
#define MANUFACTURER_ID 0x004C
// AirLocate UUID: E2C56DB5-DFFB-48D2-B060-D0F5A71096E0
uint8_t beaconUuid[16] =
{
0xE2, 0xC5, 0x6D, 0xB5, 0xDF, 0xFB, 0x48, 0xD2,
0xB0, 0x60, 0xD0, 0xF5, 0xA7, 0x10, 0x96, 0xE0,
};
// A valid Beacon packet consists of the following information:
// UUID, Major, Minor, RSSI @ 1M
BLEBeacon beacon(beaconUuid, 0x0000, 0x0000, -54);
void setup()
{
// Serial.begin(115200);
// while ( !Serial ) delay(10); // for nrf52840 with native usb
//
// Serial.println("Bluefruit52 Beacon Example");
// Serial.println("--------------------------\n");
Bluefruit.begin();
// off Blue LED for lowest power consumption
Bluefruit.autoConnLed(false);
// Set max power. Accepted values are: -40, -30, -20, -16, -12, -8, -4, 0, 4
Bluefruit.setTxPower(0);
Bluefruit.setName("Current Test");
// Manufacturer ID is required for Manufacturer Specific Data
beacon.setManufacturer(MANUFACTURER_ID);
// Setup the advertising packet
startAdv();
//Serial.println("Broadcasting beacon, open your beacon app to test");
// Suspend Loop() to save power, since we didn't have any code there
//suspendLoop();
Serial.end();
sd_power_mode_set(NRF_POWER_MODE_LOWPWR);
sd_power_dcdc_mode_set(NRF_POWER_DCDC_ENABLE);
}
void startAdv(void)
{
// Advertising packet
// Set the beacon payload using the BLEBeacon class populated
// earlier in this example
Bluefruit.Advertising.setBeacon(beacon);
// Secondary Scan Response packet (optional)
// Since there is no room for 'Name' in Advertising packet
Bluefruit.ScanResponse.addName();
/* Start Advertising
* - Enable auto advertising if disconnected
* - Timeout for fast mode is 30 seconds
* - Start(timeout) with timeout = 0 will advertise forever (until connected)
*
* Apple Beacon specs
* - Type: Non connectable, undirected
* - Fixed interval: 100 ms -> fast = slow = 100 ms
*/
// Bluefruit.Advertising.setType(BLE_GAP_ADV_TYPE_ADV_NONCONN_IND);
Bluefruit.Advertising.restartOnDisconnect(true);
//Bluefruit.Advertising.setInterval(160, 160); // in unit of 0.625 ms 100ms
//Bluefruit.Advertising.setInterval(200, 400); // in unit of 0.625 ms 125ms
Bluefruit.Advertising.setInterval(1600, 1600); // in unit of 0.625 ms 1 second
//Bluefruit.Advertising.setInterval(16000, 16000); // in unit of 0.625 ms 10 second
Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
}
void loop()
{
waitForEvent(); // current about 70ua, using a uCurrent gold into a Fluke 179 in averaging mode
//delay(100); // current about 410ua, with above, FreeRTOSConfig.h #define configUSE_TICKLESS_IDLE 1 is set
}`
Hello!
With the latest firmware, it seems that power consumption increases as softdevice is turned on.
https://devzone.nordicsemi.com/f/nordic-q-a/35073/high-power-consumption-of-softdevice/136048#136048
In my environment power consumption has been reduced by rewriting port_cmsis_systick.c
as written on this link.
Hello!
With the latest firmware, it seems that power consumption increases as softdevice is turned on.
https://devzone.nordicsemi.com/f/nordic-q-a/35073/high-power-consumption-of-softdevice/136048#136048
In my environment power consumption has been reduced by rewriting
port_cmsis_systick.c
as written on this link.
I looked at that and it wasn't entirely clear how it would impact the delay function. Is that what you observed?
@hathach could you follow up on my earlier question directed to you?
some Measurements with my NRF52832 module:
void loop() { // some other stuff to do... sd_power_mode_set(NRF_POWER_MODE_LOWPWR); waitForEvent(); }
i get arround 7µA current consumption (BLE advertising). This is the same value when i used RedBear Lib. Settings: 2 sec advertise interval 4HZ RTOS Tick Rate (cant get lower) no LED, no Serial, No I2C, No GPIOs
with delay(1000) in loop() i get arround 2000µA! suspendLoop() i get arround 1000µA!
4HZ RTOS Tick Rate (cant get lower) no LED, no Serial, No I2C, No GPIOs
with delay(1000) in loop() i get arround 2000µA! suspendLoop() i get arround 1000µA!
@ericlangel
Thank you. Can you post how you are setting RTOS tick rate? I know from scope measurement with waitForevent() it is 1khz so I think this is real key here. Or better yet post your example please.
I was able to reduce delay current in loop some by adding the idle task but as you say it is still quite high. I think your method may be the best. Hope you can reply. Thanks
/**
* RTOS Idle callback is automatically invoked by FreeRTOS
* when there are no active threads. E.g when loop() calls delay() and
* there is no bluetooth or hw event. This is the ideal place to handle
* background data.
*
* NOTE: FreeRTOS is configured as tickless idle mode. After this callback
* is executed, if there is time, freeRTOS kernel will go into low power mode.
* Therefore waitForEvent() should not be called in this callback.
* http://www.freertos.org/low-power-tickless-rtos.html
*
* WARNING: This function MUST NOT call any blocking FreeRTOS API
* such as delay(), xSemaphoreTake() etc ... for more information
* http://www.freertos.org/a00016.html
*/
void rtos_idle_callback(void)
{
// Don't call any other FreeRTOS blocking API()
// Perform background task(s) here
}
Hello wb8wka
you need to modify the RTOS Config Header
... adafruit\hardware\nrf52\0.9.3\cores\nRF5\freertos\config\FreeRTOSConfig.h
A Rate between 4 Hz and 10Hz uses arround 7µA on my Hardware (just the NRF52Module and some pull resistors @ 3,7V) If i set the Rate <4Hz the MCU seem to get stuck somewhere.
please post a reply with your current consumption with Lower RTOS TickRate
please post a reply with your current consumption with Lower RTOS TickRate
@ericlangel
average is now 36ua with your mods and the beacon rate at 2000ms. However, I only have the serial port off and still have I2C on. I need to read I2C sensor about every 30 seconds (not doing that yet) BLE beacon working correctly.
On my scope trace I am still seeing wakups ~1ms but they are not as "dense" as when tick was at 1024.
Thank you this is very good find, it is late so I will exam more later in the day.
@ericlangel
With less sleepy eyes, I'm seeing ~9ua average now. That's as before. Also the scope is less active, much closer to a current spike every 250ms which is what I would expect. I'm thinking perhaps I didn't allow all the caps to fully drain and something was in a higher current mode. I did see you were on 0.9.3 (I was on 0.9.2) but I did verify before updating. Didn't make any difference.
Now to make it do something useful. I hope to read a sensor and update the BLE advertisement.
I have to say i'm tired with this nrf52:) Guys help, i think i've already tried everything and my current consumption is to big.
#include <bluefruit.h>
#define MANUFACTURER_ID 0x004C
// AirLocate UUID: E2C56DB5-DFFB-48D2-B060-D0F5A71096E0
uint8_t beaconUuid[16] =
{
0xE2, 0xC5, 0x6D, 0xB5, 0xDF, 0xFB, 0x48, 0xD2,
0xB0, 0x60, 0xD0, 0xF5, 0xA7, 0x10, 0x96, 0xE0,
};
BLEBeacon beacon(beaconUuid, 0x0000, 0x0000, -54);
void setup()
{
Bluefruit.begin();
Bluefruit.autoConnLed(false);
Bluefruit.setTxPower(0);
Bluefruit.setName("Bluefruit52");
beacon.setManufacturer(MANUFACTURER_ID);
// Setup the advertising packet
startAdv();
sd_power_mode_set(NRF_POWER_MODE_LOWPWR);
sd_power_dcdc_mode_set(NRF_POWER_DCDC_ENABLE);
Serial.end();
//suspendLoop();
}
void startAdv(void){
Bluefruit.Advertising.setBeacon(beacon);
Bluefruit.ScanResponse.addName();
//Bluefruit.Advertising.setType(BLE_GAP_ADV_TYPE_ADV_NONCONN_IND);
Bluefruit.Advertising.restartOnDisconnect(true);
Bluefruit.Advertising.setInterval(8000, 8000); // in unit of 0.625 ms
Bluefruit.Advertising.setFastTimeout(5); // number of seconds in fast mode
Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
}
void loop(){
__set_FPSCR(__get_FPSCR() & ~(0x0000009F));
(void) __get_FPSCR();
NVIC_ClearPendingIRQ(FPU_IRQn);
sd_power_mode_set(NRF_POWER_MODE_LOWPWR);
waitForEvent();
//delay(1000);
// loop is already suspended, CPU will not run loop() at all
}
Ive change this in rtos_cmsis_systick.c
`#if 1 // With FreeRTOS sd_app_evt_wait increases power consumption with FreeRTOS compared to _WFE (NRFFOSDK-11174)
and of course systickrate
#define configTICK_RATE_HZ 4//1024
My consumption:
@monsunek which Hardware do u use? original Adafruit feather?
This two
The Feather's 3V3 Voltage Regulator has a Quiescent Current Typ. 55µA (max. 80µA) The CP2104 has Input Leakage Current of 25µA to 50µA
So...your Feather is working as expected
I thought CP2104 in rev G. is supplied from Vbus(usb) only when connected. Or do you mean leakage through TX RX pins? Putting those pins in nRF as input pulledup should help? I'm making thing like that with SD card in sleep period, which give me additional 100uA.
i think i found something for better Power consumption:
vPortSuppressTicksAndSleep(250); sd_app_evt_wait();
This stops FreeRTOS Tick Rate for 250ms. I actually get 4 Wakeups in 1 second with a Tick Rate in Config.h of 1024!
of course 250ms can be set to higher or lower values.
in the next days i will do some current measurements. Attention: this is tested with 0.9.1 In the next Days i will test it with 0.10.1
Just want to warn you 0.10.1 added lots of API changes. There will be more coming in the future releated to usb prph.
vPortSuppressTicksAndSleep(250); sd_app_evt_wait();
vPortSuppressTicksAndSleep internally calls __WFE() so I think that sd_app_evt_wait will only be executed after the system returns from its sleep period; I might be wrong there. Still, I don't think you should do this, see below.
This stops FreeRTOS Tick Rate for 250ms. I actually get 4 Wakeups in 1 second with a Tick Rate in Config.h of 1024!
of course 250ms can be set to higher or lower values.
After deep-diving in freeRTOS's documentation and the port's code, I'm going to say "don't do this". Yes, it does precisely what you want: It suspends the system tick for 250ms, and sleeps for that time. However, that function is literally what tickless-configured freeRTOS does by default, but properly, if only the idle task can be run and (in the case of this library) 2 tick periods (so 2ms here) are expected to pass before it has to wake up again. Note that this also means that lowering the tick rate to 4Hz will effectively mean for all intents and purposes your device never goes into this mode.
freeRTOS will calculate the time it should sleep, also setting up a timer to wake the system based on when it knows it will need to wake; or sleeping indefinitely if no timers are active, and no tasks are due to become runnable at a fixed time in the future.
What you should do instead, and has been hinted at a few times, is make proper use of interrupts, timers, tasks, and callbacks. Stop thinking about loop()
as this special thing that always runs on the bare metal -- that's not how this system works. Instead, consider that you are running on top of a full-fledged operating system that has proper task management. loop()
on this system is just another task. suspendLoop()
shows this: it simply calls vTaskSuspend(_loopHandle);
. What's currently missing, if you insist on using loop()
, is a function resumeLoop()
to be called from an ISR or timer callback. However, there's absolutely no reason you could not just set this up as a timer callback in the first place. Just write your application code in a simple function, as though it was loop()
, but don't try anything fancy with delay()
or __WFE()
or whatever. Define a SoftwareTimer with that function as callback and a period of 250ms in Setup()
. Start that timer, and end Setup()
with a call to suspendLoop()
.
And if you don't even need that, and only need to respond on inputs changing, as I do in my project, consider using interrupts. The only working example of this I currently have is
https://github.com/MacGyverNL/bluepedal/blob/02213ee9dcc495ccdc47f572892f7388aac09a55/bluepedal/bluepedal.ino
It's not a minimal example, but it should get the point across. Note I'm firing off timers in those interrupts, because these are bouncy buttons and I actually want to wait 3ms after the last interrupt fires before considering it as "finished". This is one way to do it if you have a critical part of your interrupt (e.g. the incrementing of a counter for every interrupt fired) and a non-critical part (e.g. sending stuff over bluetooth). Another way is using vTaskNotifyGiveFromISR
if you just want the handler of the non-critical part to fire as soon as it can. And if you have no critical part, consider using ISR_DEFERRED | <mode>
when calling attachInterrupt
, that will queue up a task for the entire handling of the interrupt; as though you'd only called vTaskNotifyGiveFromISR
in a normal ISR.
Granted, this library is currently missing quite a bit of glue code, as well as examples (e.g. I'm at a loss w.r.t whether I could use ada_callback instead of the freeRTOS code I'm currently using) and you may find yourself calling directly into freeRTOS's API instead, but I'm hoping that with more people figuring out what they actually need here, that glue code and documentation will appear.
@MacGyverNL
thank you for your thoughts. I will do some tests on that.
But the Last time i played around with suspendLoop(), i had a current of 1000µA! But it should be around 5µA. So vPortSuppressTicksAndSleep(250) or 4Hz Tick rate was a fast an easy code to get down to 5µA
But the Last time i played around with suspendLoop(), i had a current of 1000µA! But it should be around 5µA. So vPortSuppressTicksAndSleep(250) or 4Hz Tick rate was a fast an easy code to get down to 5µA
That implies that, for some reason, freeRTOS isn't sleeping by itself on a 1024Hz tick rate and suspendLoop in that situation. Would be interesting to figure out why that might be happening. I don't have the power analysis tooling for precise measurements, but afaict the idle task callback gets called at least once before the system sleeps; which has allowed some rudimentary sleep behaviour analysis by toggling an LED pin in it.
I had the same experience with suspendloop although my knowledge at the time was minimal.
On Mon, May 6, 2019 at 8:48 AM Pol Van Aubel notifications@github.com wrote:
But the Last time i played around with suspendLoop(), i had a current of 1000µA! But it should be around 5µA. So vPortSuppressTicksAndSleep(250) or 4Hz Tick rate was a fast an easy code to get down to 5µA
That implies that, for some reason, freeRTOS isn't sleeping by itself on a 1024Hz tick rate and suspendLoop in that situation. Would be interesting to figure out why that might be happening. I don't have the power analysis tooling for precise measurements, but afaict the idle task callback gets called at least once before the system sleeps; which has allowed some rudimentary sleep behaviour analysis by toggling an LED pin in it.
— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/adafruit/Adafruit_nRF52_Arduino/issues/165#issuecomment-489608049, or mute the thread https://github.com/notifications/unsubscribe-auth/ABQKNA5BNSCSUDT2XTTDORLPUASLLANCNFSM4FLLTOQA .
So i just did the Test with suspendLoop()
its called as the last command in Setup() and in loop()
without suspendLoop() -> around 350µA with suspendLoop() -> around 1000µA
i just added suspendLoop()...nothing else is changed. and....loop() is not running!
So suspendLoop() doesn't save current.
That makes no sense. Could you post the entire sketch, along with any changes you've made to config (e.g. lowering tick rate)?
@MacGyverNL
This is good low cost tool for ua current measurements;
https://lowpowerlab.com/guide/currentranger/
I use it with meter in averaging mode. To use with scope you will have to float it (use a battery to power NRF52).
The current ranger does appear to be more useful than the uCurrent. I have a ucurrent and it's not trivial to use because it's not auto-ranging.
I also have a power profiler from nordic. Seeing the actual current over time is very insightful; especially with recurring tasks. Very often, I have observed how making small changes in the code impacts the "shape" of power consumption. There are "High Current" periods and "Low Current" periods. Mapping these periods to code helps in understand what really helps and what doesn't. It's the combination of time spend in each period as well as the average current drawn during each period that really impacts the total average current as seen on a multimeter.
Looking at the time element helps a lot. The nordic power profiler also needs a nrf52832 dk. The combination isn't the cheapest but if you don't have a scope, and really want to understand your power consumption, it's a worthwhile investment.
On Tue, 7 May 2019 at 10:08, wb8wka notifications@github.com wrote:
@MacGyverNL https://github.com/MacGyverNL
This is good low cost tool for ua current measurements;
https://lowpowerlab.com/guide/currentranger/
I use it with meter in averaging mode. To use with scope you will have to float it (use a battery to power NRF52).
— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/adafruit/Adafruit_nRF52_Arduino/issues/165#issuecomment-490145410, or mute the thread https://github.com/notifications/unsubscribe-auth/AAIYW6EZJM7S5GTMWR7SNLLPUGSRBANCNFSM4FLLTOQA .
-- Pierre
@jpconstantineau
Good comments. I've got a power profiler from Nordic although I use the integrate math function on my scope more since I'm working with custom boards.
However for the gross differences being discussed here even a simple meter would quickly show the differences with suspendLoop()
Sure, but looking at what suspendLoop does, it just suspends that task. To figure out why that leads to a 650µA current draw, it would be very helpful to be able to monitor the shape of power consumption.
For example: Maybe it sleeps more often, but it actually draws more current than desirable when going to sleep / resuming from sleep -- in which case, figuring out how many idle ticks would need to pass before a net gain is had would be ideal.
It would be convenient if everybody would include information about CPU and Hardware type on which you are making tests.
so, i just tested the Beacon Example from Version 10.1 the only change: i stopped Serial with Serial.end()
with Suspendloop() at the end of Setup() i get 800-900µA with waitforevent() in the loop() i get around 300µA with waitforevent() and vPortSuppressTicksAndSleep(250) in the loop() i get also 800-900µA with waitforevent() in the loop() and Tickrate = 4 i get around 130µA with waitforevent() in the loop() and Tickrate = 4 and advertiseinterval = 2sek i get around 5-7µA
finaly.....suspendloop() doesn't save current vPortSuppressTicksAndSleep(250) doesn't save current
MCU: NRF52832 Board: Custom ( Taiyo Yuden NRF52832 Module with external 32khz and external LC for DCDC)
Hi. This's so interesting around power consumption. I tried it on Board version 0.11.0 with all you guys suggestion. Looks like waitforevent() doesn't help any more. With delay() Tickrate =4 advertiseinterval=2s. I get around 500-700uF. What should be the best board version should I use? 10.1 9.3 9.1 Also is bootloader version matter? Mine is 0.2.11 SoftDrive s132 6.1.1
Thanks
For the keyboard code I am maintaining, low power consumption is about 1-1.5mA average. When power consumption is "broken" it usually increases the average to 7.5mA. I do have code to go in "deep sleep" with a wake-up on keypress. In deep sleep, current is on the order of 1uA.
I was able to re-gain my low power consumption with BSP 0.11.0 by:
1- suspending the main loop in setup (last line of setup) suspendLoop();
2 - create software timers for specific tasks (in setup) batterytimer.begin(30*1000, batterytimer_callback); //update battery service every 30 seconds. batterytimer.start();
3 - Add the following code at the end of each timer callbacks: sd_power_mode_set(NRF_POWER_MODE_LOWPWR); sd_app_evt_wait();
On Tue, 25 Jun 2019 at 15:26, trungdn notifications@github.com wrote:
Hi. This's so interesting around power consumption. I tried it on Board version 0.11.0 with all you guys suggestion. Looks like waitforevent() doesn't help any more. With delay() Tickrate =4 advertiseinterval=2s. I get around 500-700uF. What should be the best board version should I use? 10.1 9.3 9.1 Also is bootloader version matter? Mine is 0.2.11 SoftDrive s132 6.1.1
Thanks
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/adafruit/Adafruit_nRF52_Arduino/issues/165?email_source=notifications&email_token=AAIYW6GE2EIEKVQ4FOUNXH3P4KEQHA5CNFSM4FLLTOQKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODYRUTFA#issuecomment-505629076, or mute the thread https://github.com/notifications/unsubscribe-auth/AAIYW6HYVI4RN5URETBJZHLP4KEQHANCNFSM4FLLTOQA .
-- Pierre
Thanks @pbecchi for raising this issue and share your experience with the power consumption. You are right with your observation, I will throw a bit more detail where I could.
- When ble radio is active (prph and central), it will consume much more power. I haven't looked at the nordic specs on those number. So it is a TODO for us.
- delay() in your library is more than delay as you figure out, more like sleep() now. Since we implement freeRTOS tickless https://www.freertos.org/low-power-tickless-rtos.html Everytime delay() is invoke it will put mcu into decent sleep mode (waitForEvent() ) an only wake up a few ticks before the time of scheduled action. It is all handled under the hood, man we should call it sleep() :D . It is a feature point in our upcoming "coding guideline for low power" tutorial. However the longer you delay/sleep the lower responsiveness of the device.
- For serial draining, are you testing with the later revision of the power, the previous version has an hw issue that make cp2104 constantly draw power even not enabled. Too bad, I don't even have the later revision myself to test with for now :( . However with the debug = 0, the serial shouldn't ever be used. I could double check it later.
I have also wanted to test more with power consumption and write an tutorial for it. But we are too busy for now with the upcoming nrf52840, which we will need do low power, so we wait until it comes out to test with. This will serve as notes to ourself to improve it later.
i would like to ask a question slightly out of topic but still related to some degree :) at the end you mentioned about lower responsiveness of the nrf which i really want to avoid in my RC car remote project(snappy and responsive connection is what im after). To people who dont care about power consumption and want max responsiveness is it enough to avoid delays in the main loop? thanks @hathach
Hi, i have read some issues related with the power consumption and i have no clear how to do a well setup to use the Adafruit with a battery. I did some tests with "standard" code but i see that the lipo batt is drained too fast, so my questions are below:
Should i send a command code from my controller device (Android phone) to set the Adafruit as some as a "standby mode"? I mean if exists something like power off and power on by BT commands. I do not if it is the called as "sleep mode" and "wake up"
Should i add delays in the loop code in order to have less consumption? I've read this thread but i do not see clear if these are good practices reccommeded by Adafruit
Exists any convenction to proceed when the lipo batt is almost empty? i mean, advice to the user when batt is under 5%
When i put the charger, the lipo batt will be recharging automatically? Or maybe i should to manage something programatically.
I am newby using this Adafruit BT device and i need some patterns to start working well with it. Thanks in advance
Since long time I am fighting to lower power consumption using this library to the levels reachable with Sdk examples! I have run several examples, testing the uA level in different type of code. If we don't use BLE libraries uA are very near to the one expected , normally few uA when we are in low power mode. But if we use BLE consumption get well above 1mA so about 100 times more that expected! I have used the dual role BLE uart example and these are my findings: -to enter low power mode you have to add delay() in the main loop , the longest the milliseconds the lowest the power drain. -all Ble central related functions are taking quite a bit of mA -keeping only BLE peripheral functions, with delay(100) will give about 600uA that is about what is expected (100 uA+500uA for Serial uart) -taking out all Serial.begin and Serial.print from the example INCREASE the power drain to about 2mA while should be reduced by 500uA
I think this strange behaviour may only be due to some Serial debug statement present on the BLE libraries. In theory Serial debug should be fully controlled by the Tools menu setting and with debug=0 slould not be executed!