PlatformIO Community

nRF52 DK BLE can't sleep

I’m using Nordic nRF52 DK in order to make a BLE application that broadcasts data through a custom characteristic with Read and Notify properties.

I’m currently working with PlatformIO and Visual Studio Code for this project.

Project setup wizard

To measure the power consumption I am using the Power Profiler kit.

The power consumption is always above 2.3mA which is extremely high based on Online Power Profiler For Ble.

Online Power Profiler For Ble settings:

{
  "chip": "1",
  "voltage": "3",
  "dcdc": "on",
  "lf_clock": "lfrc",
  "radio_tx": "-40",
  "ble_type": "adv",
  "ble_int": "1000",
  "tx_size": "20"
}

My goal is to put the board to sleep until a new Bluetooth connection is established and then execute the eventQueue for the sensor value update and other processes. After the disconnection event the board must be put to sleep again.

First, I tried to implement sleep for an mbed sample project with BLE features BLE_BatteryLevel.

Note: I removed the blink event from the sample code.

I have added _event_queue,break_dispatch() inside onDisconnectionComplete callback function, in order to force the ble to exit from its functions.
I do not know if it is the right choice but I wanted somehow to exit ble’s event queue and let the board sleep.

OnDisconnectionComplete

I have tried the following:

  • Use a DeepSleepLock object in a block of code in order to execute sleep on its destruction
  • Using ThisThread::sleep(5s)

int main()
{
    while (true)
    {
        ThisThread::sleep_for('5s');
        {
            DeepSleepLock dp;
            BLE &ble = BLE::Instance();
            ble.onEventsToProcess(schedule_ble_events);
            BatteryDemo demo(ble, event_queue);
            demo.start();
            ThisThread::sleep_for('5s');
        }
    }
}

  • Using void sleep()
int main()
{                  
            BLE &ble = BLE::Instance();
            ble.onEventsToProcess(schedule_ble_events);
            BatteryDemo demo(ble, event_queue);
            demo.start();                               
            ble.shutdown();
            sleep();            
}

Power Profiler Screenshot from BLE onDisconection
Power Profiler Screenshot

  • Hal_sleep functions
int main()
{
    BLE &ble = BLE::Instance();
    ble.onEventsToProcess(schedule_ble_events);
    BatteryDemo demo(ble, event_queue);
    demo.start();
    ble.shutdown();
    hal_sleep();
}
  • Disable input and output using at the start of main
  mbed_file_handle(STDIN_FILENO)->enable_input(false);
  mbed_file_handle(STDIN_FILENO)->enable_output(false);
  • Adding rtos::Kernel::attach_idle_hook(&sleep); at the start of main()
int main()
{    
    rtos::Kernel::attach_idle_hook(&sleep);               
    BLE &ble = BLE::Instance();
    ble.onEventsToProcess(schedule_ble_events);
    BatteryDemo demo(ble, event_queue);
    demo.start();                               
}

Nothing seems to put the board on sleep, the power consumption is always high.

Power Profiler Screenshots

  • BLE Enabled State

enter image description here

  • BLE Disconnected state (sleep)

enter image description here

I couldn’t find any example for power consumption and sleep using BLE.

At which point exactly is the current being measured? If you are measuring the current flowing into the 5V supply of the USB port of the board as a total, then due to the linear voltage regulators to 3.3V, lit LEDs etc. there will be an additional load and quiescent currents.

I tried to measure consumption from external DUT and the consumption was the same. However, with the activation of the DCDC converter, the active consumption dropped.
My main problem is how to put the board to sleep and wake it up with a new BLE connection.

So your board is the Nordic nRF52 DK board or something custom? How is it being powered?

Since you’re using mbed-os, the RTOS is designed in such a way that it will trigger automatic sleep in the idle thread of the RTOS. You can only prevent it from sleeping by using DeepSleepLock objects or start using peripherals which would prevent the chip from deepsleep. Exact implementation details depend on the used mbed-os version and platformio.ini configuration, both of which you didn’t show. What’s your platformio.ini and the framework-mbedos package version that is being shown at the start of the compilation?

The board is Nordic nRF52 DK and it is powered by USB. The active consumption was measured with PPK which measures only the current flowing through nRF52832 chip. The problem with the unexpected consumption was solved by enabling the DCDC converter.

I am using: platformio/framework-mbed 6.60200.200722 @ ~6.60200.0 [Up-to-date]

My platformio.ini file:

[env:nrf52_dk]
platform = nordicnrf52
board = nrf52_dk
framework = mbed

My mbed_app.json

{
    "target_overrides": {
        "NRF52_DK": {
            "target.features_add": ["BLE"]
        }
    }
}

BUT my issue still remains with the Board, which I couldn’t find a way to put to sleep and wait until a new BLE connection is established (in order to wake up the board from sleep).
I tried to implement BLE with System modes (on/off) nrf5x-powerdown-examples.
Unfortunately without breaking the _eventQueue inside OnDisconnectionComplete event, I cannot escape from demo.start() and continue in main()

    void onDisconnectionComplete(const ble::DisconnectionCompleteEvent &)
    {
        printf("onDisconnectionComplete!\n");
        _ble.gap().startAdvertising(ble::LEGACY_ADVERTISING_HANDLE);
        _event_queue.cancel(_update_sensor_event);
        _event_queue.break_dispatch();
    }
int main()
{
    BLE &ble = BLE::Instance();
    ble.onEventsToProcess(schedule_ble_events);
    BatteryDemo demo(ble, event_queue);
    demo.start();
    while (1)
    {
        // Enter CONSTLAT mode if desired, otherwise LOWPWR mode will be used (LOWPWR is recommended for most applications)
        NRF_POWER->TASKS_CONSTLAT = 1;

        // Enter System ON sleep mode
        __WFE();
        __SEV();
        __WFE();
    }
}

For questions on mbed-os it would be best to ask the mbed-os people how to do that in mbed-os 6.0.2. PlatformIO just uses the mbed_app.json you give it – configuration internals then happen inside mbed code.

On the off-chance that it has something to do with PlatformIO that won’t enable the sleep, I suggest you directly use mbed-os for a small test program and test power consumption there. As I said, sleep in mbed-os is automatic – your test program with the deep sleep locks already looked good for testing the difference in non-sleep and sleep mode there.

Hi @mouratidisa can you share how you are enabling DCDC converter either from main
NRF_POWER->DCDCEN = 1;
or at some other location in code.
I am also running with same problem and i am experiencing current consumption of 1.5mA during Advertisement.