5 years, 6 months ago.

Sleep BLE

Hi all,

I have following problem and I am just not able to solve it.

I want to sleep() with my nrf51822 and wake up after a rise on a interrupt pin.

InterruptIn pulse(p19);

void Blau() 
{
  eventQueue.call_every(1000, periodicCallback); // this is from an example for BLE
  BLE &ble = BLE::Instance(); // this is from an example for BLE
  ble.onEventsToProcess(scheduleBleEventsProcessing); // this is from an example for BLE
  ble.init(bleInitComplete); // this is from an example for BLE
  eventQueue.dispatch_forever(); // this is from an example for BLE
}

int main()
{
  pulse.rise(&Blau); // If Interrupt rises sleep is interrupted and "Blau" starts.
  while(1){
          sleep();       //Sleep to save power, Interrupted by Ticker and Pulse events
        }
}

Can I wake up this way? If I do that the periodicCallback does not work. If I put all the stuff form the Blau in the main and kill the sleep() it works.

here the code I wanted to use

/* mbed Microcontroller Library
 * Copyright (c) 2006-2013 ARM Limited
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <mbed_events.h>
#include <rtos.h>
#include "mbed.h"
#include "ble/BLE.h"
#include "ble/services/HealthThermometerService.h"

InterruptIn pulse(p19);
DigitalOut led1(LED1, 0);
DigitalOut led2(p22, 0);
DigitalOut led3(p18, 0);

const static char     DEVICE_NAME[]        = "Halloneu";
static const uint16_t uuid16_list[]        = {GattService::UUID_HEALTH_THERMOMETER_SERVICE};

static float                     currentTemperature   = 39.6;
static HealthThermometerService *thermometerServicePtr;

static EventQueue eventQueue(/* event count */ 16 * EVENTS_EVENT_SIZE);

/* Restart Advertising on disconnection*/
void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *)
{
    BLE::Instance().gap().startAdvertising();
}

void updateSensorValue(void) {
    /* Do blocking calls or whatever is necessary for sensor polling.
       In our case, we simply update the Temperature measurement. */
    currentTemperature = currentTemperature+1;
    thermometerServicePtr->updateTemperature(currentTemperature);
}

void periodicCallback(void)
{
    led1 = !led1; /* Do blinky on LED1 while we're waiting for BLE events */

    if (BLE::Instance().gap().getState().connected) {

        eventQueue.call(updateSensorValue);
      }
    }
void onBleInitError(BLE &ble, ble_error_t error)
{
   /* Initialization error handling should go here */
}

void bleInitComplete(BLE::InitializationCompleteCallbackContext *params)
{
    BLE&        ble   = params->ble;
    ble_error_t error = params->error;

    if (error != BLE_ERROR_NONE) {
        onBleInitError(ble, error);
        return;
    }

    if (ble.getInstanceID() != BLE::DEFAULT_INSTANCE) {
        return;
    }

    ble.gap().onDisconnection(disconnectionCallback);

    /* Setup primary service. */
    thermometerServicePtr = new HealthThermometerService(ble, currentTemperature, HealthThermometerService::LOCATION_EAR);

    /* setup advertising */
    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list));
    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::THERMOMETER_EAR);
    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));
    ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
    ble.gap().setAdvertisingInterval(1000); /* 1000ms */
    ble.gap().startAdvertising();
}

void scheduleBleEventsProcessing(BLE::OnEventsToProcessCallbackContext* context) {
    BLE &ble = BLE::Instance();
    eventQueue.call(Callback<void()>(&ble, &BLE::processEvents));
}
void Button();
void Hilfe();

void Hilfe(void) {
  exit(0);
  //led2=0;
  //led3=0;
}
void Blau() {
  eventQueue.call_every(1000, periodicCallback);
  //eventQueue.call_every(20000, Hilfe); // nach 200000 wird hilfe gecallt.
  BLE &ble = BLE::Instance();
  ble.onEventsToProcess(scheduleBleEventsProcessing);
  ble.init(bleInitComplete);
  eventQueue.dispatch_forever();
}

int main()
{
  pulse.rise(&Blau); // If Interrupt rises sleep is interrupted
  while(1){
          sleep();       //Sleep to save power, Interrupted by Ticker and Pulse events
        }
}

1 Answer

5 years, 5 months ago.

Hi Daniel,

We've run your desired code and the issue is that you are trying to run the entire BLE example all within an interrupt handler. As the Nordic SoftDevice utilizes interrupts itself, likely some interrupts are not getting handled in a timely fashion so the example isn't running properly. FWIW we do see the board advertising as "Halloneu" in the nRF Connect Android application but we can't establish a connection to it.

The Mbed OS itself is also energy aware, so you shouldn't need to explicitly call sleep(). When the OS is idle it will automatically enter the lowest possible idle or sleep mode.

Regards,

Ralph, Team Mbed

Accepted Answer

thanks a lot for the fast reaction. As I understand the module should consume a few uA let out the leds if I do not run the BLE?

posted by Daniel Blumer 04 Oct 2018