ARMmbed / mbed-os

Arm Mbed OS is a platform operating system designed for the internet of things
https://mbed.com
Other
4.67k stars 2.98k forks source link

BLE power consumption using CORDIO stack too high #10669

Open sagrebin opened 5 years ago

sagrebin commented 5 years ago

Description of defect

I've cloned the mbed-os-example-ble repo and removed the LED blinking code and the print statements. When I run the application on my dev board and use nordics power profiler I get an average of 1mA when advertising (advertising interval: 2 sec). I did the same with the with the deprecated sample BLE_BatteryLevel which uses nordics soft device and I get around 20uA when advertising. I use a custom dev board with the ublox NINA-B112 module, there are no other components on the board which could consume power.

Target(s) affected by this defect ?

NRF52_DK

Toolchain(s) (name and version) displaying this defect ?

GCC_ARM

What version of Mbed-os are you using (tag or sha) ?

a4738fa9a8

What version(s) of tools are you using. List all that apply (E.g. mbed-cli)

mbed-cli 1.10.0

How is this defect reproduced ?

See the description above

40Grit commented 5 years ago

If debugging with an .svd loaded,

are you able to confirm which peripherals are enabled and running between the two examples?

Also would be interesting to see the clock configurations between the two.

40Grit commented 5 years ago

Mistyped .svd above.

yogeshk19 commented 5 years ago

@40Grit We are seeing similar power consumption and at times even higher than 1ma during advertisements. One of the other issues, had listed out disabling the cryptocell and here is what the mbed_app.json looks like. Ours is a custom board with NRF52840 BLE module. We are using Cordio API without the Nordic Softdevice.

{ "target_overrides": { "NRF52840_DK": { "target.features_add": ["BLE"], "target.extra_labels_add": ["CORDIO", "CORDIO_LL", "SOFTDEVICE_NONE", "NORDIC_CORDIO"], "target.features_remove": ["CRYPTOCELL310"], "target.macros_remove": ["MBEDTLS_CONFIG_HW_SUPPORT"], "target.extra_labels_remove": ["SOFTDEVICE_COMMON", "SOFTDEVICE_S140_FULL", "NORDIC_SOFTDEVICE"], "platform.stdio-baud-rate": 115200, "platform.default-serial-baud-rate": 115200, "target.console-uart-flow-control": null } } } Thanks, Yogesh

40Grit commented 5 years ago

My questions above are wondering what soft device does with the clocks/peripherals/radio settings in order have significantly lower power consumption than cordio stack.

0xc0170 commented 5 years ago

My questions above are wondering what soft device does with the clocks/peripherals/radio settings in order have significantly lower power consumption than cordio stack.

cc @ARMmbed/mbed-os-pan

40Grit commented 5 years ago

@sagrebin , @yogeshk19 To provide further clarity to my vague posts above.

Are either of you able to dump the peripheral registers when using softdevice and when using cordio?

The diff between the two dumps could provide some insight since the softdevice sources are closed.

yogeshk19 commented 5 years ago

@40Grit Sorry I haven't had a chance to dump the peripheral registers. I am planning on re-running my power draw tests again after the next mbed-os release which is supposed to have updates to hci driver i believe. I am not planning on using the softdevice at this point, only the Cordio API as is.

sagrebin commented 5 years ago

@40Grit I was hoping that with the arrival of nordics sdk 15 it would be fixed by unfortunately its not. I've dumped the registers: cordio: https://pastebin.com/i1q4T08m nordic SD: https://pastebin.com/47XEkrBh

pan- commented 5 years ago

From the diff it looks like the LFCLK is synthesized from the HFCLK when Cordio is used. That might be one of the cause of the high power consumption.

sagrebin commented 5 years ago

Indeed, for some reason the NRF_LF_CLK_SRC is set to CLOCK_LFCLKSRC_SRC_Synth in NRFCordioHCIDriver.cpp `#if MBED_CONF_NORDIC_NRF_LF_CLOCK_SRC == NRF_LF_SRC_SYNTH

define NRF_LF_CLK_SRC CLOCK_LFCLKSRC_SRC_Synth

` But what I don't get is why MBED_CONF_NORDIC_NRF_LF_CLOCK_SRC is set to NRF_LF_SRC_SYNTH. Every definition I can find is set to NRF_LF_SRC_XTAL

40Grit commented 5 years ago

@aglass0fmilk

ghost commented 5 years ago

@sagrebin : so you see NRF_LF_CLK_SRC set to NRF_LF_SRC_XTAL in mbed_config.h ?

kleunen commented 5 years ago

I have seen the same issue. I am not sure if it is the crystal configuration, I tried changing back the crystal to XTAL, in the initComplete of the BLE stack. But this does not seem to help.

bsturgess commented 5 years ago

Same issue here too. watching...

40Grit commented 5 years ago

The best way to get a picture of what is going on is to dump the peripheral and cpu registers between the two examples you are comparing power for.

Then do a diff of the dumps.

It needs to be considered as well that if a gpio is left in an output state it may result in leaks to other unpowered components on a board.

Additionally the pull resistors internal to the gpios for this part are pretty strong. Deffinitely confirm the state of your gpios.

bsturgess commented 5 years ago

I've checked the consumption before the ble.init and its 3ua, so roughly what it should be.

I can also see that the device just doesn't deep sleep after ble init, see logs below, 0 time in deepsleep :( ...

Results from logger Uptime: 2001 Sleep time: 1930 Deep Sleep: 0 Uptime: 4001 Sleep time: 3864 Deep Sleep: 0 Uptime: 6001 Sleep time: 5798 Deep Sleep: 0 Uptime: 8001 Sleep time: 7733 Deep Sleep: 0 Uptime: 10001 Sleep time: 9667 Deep Sleep: 0 Uptime: 12001 Sleep time: 11601 Deep Sleep: 0 Uptime: 14001 Sleep time: 13535 Deep Sleep: 0

bsturgess commented 5 years ago

What is the code for dumping the registers? Thanks

40Grit commented 5 years ago

Should be able to do it through gdb command line or pyocd. J-link commander maybe if using j-link

40Grit commented 5 years ago

you will need to load the .svd file for your target mcu

bsturgess commented 5 years ago

Is this being looked at internally by the ARM team? If so i'll just keep on using SoftDevice until resolved

40Grit commented 5 years ago

Latest news is that the BLE PAN team is busy. Also the Cordio team was let go in April and became PacketCraft Inc.

Embedded Planet, my employer, will probably be looking into this over the next couple months but no promises.

Not sure how Cordio governance is going to go moving forward. PacketCraft is probably the new maintainer.

40Grit commented 5 years ago

Also softdevice has its own RTOS internally. I have heard and experienced that it doesnt play very nice with external RTOS's.

ghost commented 5 years ago

and there's no history at their github repo https://github.com/packetcraft-inc/cordio. How can anybody really keep track of what they are up to?

pentabarf commented 4 years ago

I've checked the consumption before the ble.init and its 3ua, so roughly what it should be.

I can also see that the device just doesn't deep sleep after ble init, see logs below, 0 time in deepsleep :( ...

Results from logger Uptime: 2001 Sleep time: 1930 Deep Sleep: 0 Uptime: 4001 Sleep time: 3864 Deep Sleep: 0 Uptime: 6001 Sleep time: 5798 Deep Sleep: 0 Uptime: 8001 Sleep time: 7733 Deep Sleep: 0 Uptime: 10001 Sleep time: 9667 Deep Sleep: 0 Uptime: 12001 Sleep time: 11601 Deep Sleep: 0 Uptime: 14001 Sleep time: 13535 Deep Sleep: 0

I noticed that there is a deep sleep lock in the Cordio idle_hook. (I am using nRF52) And it gets called when there is nothing to do i guess. Possibly this has an effect on deep sleep See in mbed-os/targets/TARGET_NORDIC/TARGET_NORDIC_CORDIO/TARGET_NRF5x/NRFCordioHCIDriver.cpp

static void idle_hook(void) { [...] // critical section to complete sleep with locked deepsleep core_util_critical_section_enter(); sleep_manager_lock_deep_sleep(); sleep(); sleep_manager_unlock_deep_sleep(); core_util_critical_section_exit(); }

kleunen commented 4 years ago

@pentabarf You are right

It actually says in the documentation: https://github.com/ARMmbed/mbed-os/blob/master/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_CORDIO/TARGET_NRF5x/README.md

Resources used: HF clock is enabled

That is just complete BS, this really removes LE from BLE.

yogeshk19 commented 4 years ago

@40Grit, @pan- I was wondering based on @pentabarf and @kleunen comments, is there any progress on helping improve the power consumption? Currently our application we have built which advertises 90% of the time and 10% time stays connected, the avg. power consumption is 200 uA when advertising and 300 uA when connected using the Cordio API. When using the softdevice the power draw is around 20 uA when advertising and 9-12 uA when connected. This clearly indicates the Cordio platform is consuming more power than when just using Nordic's softdevice to build a similar application.

As mentioned by you earlier that Cordio is no longer the priority for ARM and a different company has taken over the development effort, but I am wondering when companies like mine migrated to Cordio platform assuming that this was the better platform to be on since ARM supported this new platform for BLE and that something so important as BLE Power consumption needs to be handled, what is the escalation mechanism to get either ARM or the new company to address this issue? This issue has been lingering from 9 months now, with no clear priority or resolution in sight.

Sorry just venting out!

Thanks, Yogesh

0xc0170 commented 4 years ago

Thanks @yogeshk19 for the feedback. I'll share this with relevant people.

40Grit commented 4 years ago

@yogeshk19 Contact Packetcraft. I recently talked with them about the Mbed Cordio stack integration at AIoT but forgot to mention this issue. I think they could be helpful too.

info@packercraft.com https://www.packetcraft.com/

40Grit commented 4 years ago

@AGlass0fMilk I know the magic stick has a monstrous battery but if you get a moment maybe take a look further into this?

AGlass0fMilk commented 4 years ago

@yogeshk19 Have you verified the connection and advertising parameters are the same in both applications? How are you measuring this current draw? The power profiler kit from Nordic would be ideal in this case because it can show the large spikes in current during transmission and also the low quiescent current draw.

I'll hopefully be able to look into this when I'm working more with BLE in the next few weeks.

yogeshk19 commented 4 years ago

@AGlass0fMilk Yes the device primarily connects to an IPhone or Android phone and we use the appropriate connection parameters. We didn't use the Nordic power profiler kit, we used other means to determine the average power draw. I have to say however the initial power draw was way higher with Cordio, but with the latest MBED OS and other software and hardware improvements on our side has reduced the power draw from 1.5 mA to 200 uA while advertising and connected. But as suggested by @pentabarf if the MBED OS is not entering deep sleep as expected, I am sure when the system is idle it will continue to draw power. Is this something that can be investigated and a fix for ensuring that the device enters sleep mode when idle. This seems to work effectively when using Nordics Softdevice and hence the much lower power draw?

Thanks, Yogesh

40Grit commented 4 years ago

We have struggled with NRF and deep sleep as well even without BLE being used.

Since the Port of the nrf sdk is only maintained by ARM, partners and community, there are some bugs we are all still working out. As we use different peripherals and power schemes they pop up.

If not entering deep sleep then a peripheral driver is probably setting the sleep lock.

we've found some little things like setting NFC pins to gpio save a couple uA. Might be circuit dependant though.

pentabarf commented 4 years ago

In the meantime... is there a simple way to switch back to softdevice? just changing the flags in mbed_lib.json doesn't seem to do the trick. Is the ble codebase still supporting softdevice?

kleunen commented 4 years ago

I failed to do so, i had to go a couple of version back to get a working softdevice BLE again.

kleunen commented 4 years ago

I switched back to mbed os version 5.11.5, it has the nordic softdevice. The power consumption for this version is still ok. It is rather annoying, because sometimes the mbed version gets updated to the latest version somehow, resulting in much higher power consumption.

bsturgess commented 4 years ago

Totally agree, 5.11 is the only version of mbed that can be used if you want any sensible power consumption.

Very frustrating

On Wed, 19 Feb 2020, 09:06 Wouter van Kleunen, notifications@github.com wrote:

I switched back to mbed os version 5.11.5, it has the nordic softdevice. The power consumption for this version is still ok. It is rather annoying, because sometimes the mbed version gets updated to the latest version somehow, resulting in much higher power consumption.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/ARMmbed/mbed-os/issues/10669?email_source=notifications&email_token=AAW4SXZUSCJH3S5C2GJEU4LRDTZCDA5CNFSM4HPTFNR2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEMG576A#issuecomment-588111864, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAW4SXZSVPWRI3GETUKRHY3RDTZCDANCNFSM4HPTFNRQ .

CodingGhost commented 4 years ago

any progress here? Is systemOFF mode affected by this issue? I just ported our Software to cordio and I am seeing 37uA in systemOFF mode, it was at about 0.8 before. can cordio be the cause of this?

AGlass0fMilk commented 4 years ago

any progress here? Is systemOFF mode affected by this issue? I just ported our Software to cordio and I am seeing 37uA in systemOFF mode, it was at about 0.8 before. can cordio be the cause of this?

I would check the peripherals that are still active in system off (RTC possibly) and see if they’re still enabled. Also check RAM retention settings. Lastly, make sure there weren’t any changes in how your GPIO are set during system off.

It’s possible Cordio could be changing one of these settings whereas the softdevice didn’t.

CodingGhost commented 4 years ago

I tried to disable everything I know NRF_RTC0->TASKS_STOP = 1; NRF_RTC1->TASKS_STOP = 1; NRF_CRYPTOCELL->ENABLE = 0; NRF_RADIO->TASKS_STOP = 1; //!< Peripheral power control. NRF_RADIO->POWER = 0; //!< Peripheral power control. NRF_UART0->ENABLE = 0; //!< Peripheral power control. NRF_SPI0->ENABLE = 0; //!< Peripheral power control. NRF_SPIS1->ENABLE = 0; //!< Peripheral power control. NRF_TIMER0->TASKS_STOP = 1; //!< Peripheral power control. NRF_TIMER1->TASKS_STOP = 1; //!< Peripheral power control. NRF_RNG->TASKS_STOP = 1; //!< Peripheral power control. / NRF_LPCOMP->TASKS_STOP = 1; //!< Peripheral power control. NRF_CLOCK->TASKS_HFCLKSTART = 0; NRF_CLOCK->TASKS_HFCLKSTOP = 1;

but this still gives me 20uA instead of 1.

anything I missed?

CodingGhost commented 4 years ago

so, after some testing, I could reduce the problem to following lines:

` BLE &ble = BLE::Instance(BLE::DEFAULT_INSTANCE);

volatile ble_error_t initerr = ble.init(bleInitComplete);
thread_sleep_for(2000);
ble.shutdown();

NRF_POWER->SYSTEMOFF = 1;`

What can I do about this now? what peripheral could still be active and drawing about 20uA?

Also, ofcourse systemON current is waay too high! I was at about 200uA AVG with SD, now I am at over 900uA AVG! @0xc0170

pentabarf commented 4 years ago

@CodingGhost I think you need to ENABLE RTC for Low Power Mode.

Also try to activate DC-DC when assembled: NRF_POWER->DCDCEN = 0x00000001;

And Disable NFC functionallity: NRF_UICR->NFCPINS = 0x00000000;

And disable UART in your mbed_app.json in "target_overrides":{"*":{"target.console-uart": false}}

I don't know if it is still necessary but add this to "target.macros_add":

                "DEVICE_SLEEP",
                "MBED_TICKLESS",
                "DEVICE_LPTICKER",
                "MBED_CONF_TARGET_TICKLESS_FROM_US_TICKER=0",
                "MBED_SLEEP_TRACING_ENABLED"

Then try this (without warranty for stability): comment following lines in _mbed-os/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NORDIC_CORDIO/TARGETNRF5x/NRFCordioHCIDriver.cpp

in function "static void idle_hook(void)"

core_util_critical_section_enter();
sleep_manager_lock_deep_sleep();
sleep_manager_unlock_deep_sleep();
core_util_critical_section_exit();
CodingGhost commented 4 years ago

@pentabarf You are the man! I am at 0.8uA of current again. I tried to uncomment the section again, and my current went up to 3mA?! Can I safely comment this section, for what is it good? and is this a bug?

thanks a lot!

0xc0170 commented 4 years ago

@pentabarf 💯 thanks for sharing this!

yogeshk19 commented 4 years ago

@CodingGhost you have listed out quite a number of different things you tried out to lower the current draw. My question is which change seemed to help the most to drop the current draw. Was it just commenting out the code that @pentabarf suggested? Also is the average current draw significantly lowered when advertising and connected with the changes you have tried out so far?

@pentabarf, @0xc0170 The code that was commented out, isn't it necessary for the board to enter deep sleep, when idle?

Thanks, Yogesh

pentabarf commented 4 years ago

@yogeshk19 no the function static void idle_hook(void) replaces the default idle function of mbed and as the names of the called functions say (sleep_manager_lock_deep_sleep() and sleep_manager_unlock_deep_sleep() encapsulate the sleep() function), deep sleep gets prevented. I guess this is for a stable work of BLE because wakeup from deep sleep needs some time but i have no problems with it right now. But this may depend on ble workload. Maybe someone of the developers at packetcraft can tell us more?

you can check this out with the MBED_SLEEP_TRACING_ENABLED macro. When uncommenting the lines deep sleep never gets called.

CodingGhost commented 4 years ago

@yogeshk19 I tried many different things now, all the registers I have set to disable peripheral hardware dont seem to make a difference. disabling UART makes the biggest difference, then, adding the macros saves another ~2uA. commenting the section, allows me to enter deepsleep at all after adding in the macros, I cannot imagine this is wanted behaviour, is there any way of entering systemOFF without having to modify MBED code? @0xc0170 do you possibly know which developer of packetcraft? is responsible for this? could you mention him here? for now, I will use this workaround and hope it works out.

I have to add, that I am not using the sleep() or deepsleep() function, but NRF_POWER->SYSTEMOFF = 1. I think its a bit strange that the MBED code prevents the chip from entering systemOFF, when I am setting it directly in the registers. I do not want to "sleep" I want the chip to turn off and then wake by GPIO, which works fine, but this does not have to be locked by MBED... It doesnt make sense to me.

EDIT: regarding systemON current, I have about 2mA of systemON current while advertising. This is waay to high! I tried replacing the commented section with just '__WFE();' and this got me to about 500uA of systemON current, which is ok but still higher than with Softdevice.

is this workaround dangerous? can I use it in production software?

yogeshk19 commented 4 years ago

@CodingGhost, @pentabarf None of them worked for me, infact the power draw went up by 100uA's. Although I am not testing the system power off, I am testing just plain advertisement. Currently without any of the changes, the current draw is at 250 uA's and once I add the changes you tried out it goes up to 350 uA's. At this point I am not sure what is going to get the cordio platform to operate at the softdevice levels of power draw?

@CodingGhost did you make the following change, to reduce it to 500 uAs? Also what version of mbed_os are you on? I am still on mbed-os-5.13.4.

__WFE();
// critical section to complete sleep with locked deepsleep
/core_util_critical_section_enter();
//sleep_manager_lock_deep_sleep();
sleep();
//sleep_manager_unlock_deep_sleep();
//core_util_critical_section_exit();

Thanks, Yogesh

CodingGhost commented 4 years ago

@yogeshk19 my main concerns were regarding the systemOFF state, which i am happy now with. 250uA while advertising is still better than I am doing with my 500uA. regarding the code change, I am sorry I confused you, but I misread something. I had commented everything, Includeing the sleep(); and replaced it with __WFE();, but upon further investigation, I dont think it has any benefits.

I am on MBEDOS 5.14.1

I really hope some dev at packetcraft will read through this, as I think this is a really critical issue.

yogeshk19 commented 4 years ago

I just posted a message on Packetcrafts contact us page and hopefully they would take the time to read it and do something about it and I am not sure why the MBED team which has been receiving all these messages regarding this github issue, hasn't raised it as a priority issue with the Packetcrafts team and get them to address it ASAP. At least by now we could have closed this issue and focus on developing our respective products.

Thanks, Yogesh

ladislas commented 4 years ago

I agree with @yogeshk19 and everything that has been said in this conversation. I'm cc'ing @jyi-packetcraft from Packetcraft

I'm a bit worried with Packetcrafts taking over the Cordio development. They seem to be very competent (they all have strong backgrounds and most worked for arm) but they are a startup, so what happens if they run out of business or need to focus more on they own products than on Cordio?

Cordio is supposed to be open source, and in a way it is (https://github.com/packetcraft-inc/cordio) but there is no way to collaborate: we can't open issues and PR are not considered at all (except for the "next version" whatever that means).

A clear roadmap should be available, people should be able to contribute, ask questions, raise issues to make Cordio better. Cordio should be like mbed, with an incredible team doing the foundation work, and a lot of external contributors giving them a hand.

With the current situation, as a business it's hard to make the decision to use Cordio in a real product as I don't have any way of knowing that Cordio will be maintained in the future.