Fix for nRF51822: InterruptIn not triggering / Falling asleep 10 minutes after booting

28 Nov 2017

Hi everybody,

1. I just found out that the mbed OS 5.2.1 release of Oct 2016 (realease 128) introduced an issue on the nRF51822 - The non-triggering of InterruptIn associated callbacks. I'm testing this with setting .rise() upon one of these variables, associated to a physical button. The device doesn't react to the button's click since this release.

2. In another hand this release corrected an issue on the same microcontroller - Before this release the device would apparently go to sleep (stopping to transmit BLE signals and to react to InterruptIn's) after 8 to 10 minutes from booting.

Does anybody have a hint on which may be the cause of the issue (1.) or which part of the mbed OS 5.2.1 release has been responsible to solve issue (2.) so that I can fork from the previous release?

Thanks!

include the mbed library with this snippet

#define FPU_EXCEPTION_MASK 0x0000009F

#ifdef NRF52
    /* Clear exceptions and PendingIRQ from the FPU unit */
    __set_FPSCR(__get_FPSCR()  & ~(FPU_EXCEPTION_MASK));
    (void) __get_FPSCR();
    NVIC_ClearPendingIRQ(FPU_IRQn);
#endif

#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <sstream>
#include <string.h>
#include <string> 
#include <vector>
#include <ctime>

#include "mbed.h"
#include "ble/BLE.h"
#include "EddystoneService.h"

extern "C" {
    #include "softdevice_handler.h"
    #include "nrf_error.h"
    #include "nrf_ble_gap.h"
    #include "app_scheduler.h"
}

/****************************************************************************************************
 * Global Variables
 ****************************************************************************************************/

EddystoneService *      eddyServicePtr;

( ... )

static bool             triggerA = false;
static bool             triggerB = false;

static DigitalOut       alivenessLED(LED1, 1);

int                     scoreA = 0;
int                     scoreB = 0;

InterruptIn             buttonA(p4);
InterruptIn             buttonB(p5);

( ... )

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

    if (error != BLE_ERROR_NONE) {
        onBleInitError(initContext);
        return;
    }
   
   ( ... )

    /* Set everything to defaults */
    eddyServicePtr = new EddystoneService(ble, defaultAdvPowerLevels, radioPowerLevels);
    
    /* Updates the current_match_url with the current match score */
    const char *current_match_url;
    
   ( ... )
    
    /* Set default URL, UID and TLM frame data if not initialized through the config service */
    eddyServicePtr->setURLData(current_match_url);
    eddyServicePtr->setUIDData(&uidNamespaceID, &uidInstanceID);
    eddyServicePtr->setTLMData(tlmVersion);

    /* Set battery voltage and temperature callbacks */
    eddyServicePtr->onTLMBatteryVoltageUpdate(tlmBatteryVoltageCallback);
    eddyServicePtr->onTLMBeaconTemperatureUpdate(tlmBeaconTemperatureCallback);
    
    /* Adjusts TXPower to a higher setting */
    ble.gap().setTxPower(4); 
    
    /* Adjusts the advertised name */
    ble.gap().setDeviceName("GoaloriaDevice");

    /* Start Eddystone in config mode */
    eddyServicePtr->startBeaconService(1, 0, 0);
}

void trigA() {
   triggerA = true;
   alivenessLED = true;
}

void trigB() {
   triggerB = true;
   alivenessLED = true;
}

int main(void) {   
    buttonA.rise(&trigA);
    buttonB.rise(&trigB);
    
    BLE& ble = BLE::Instance(BLE::DEFAULT_INSTANCE);
    ble.init(bleInitComplete);

    /* SpinWait for initialization to complete. This is necessary because the
     * BLE object is used in the main loop below. */
    while (ble.hasInitialized()  == false) { /* spin loop */ }
    
    while (true) {
        if (triggerA) {
            /* Do blocking calls or whatever hardware-specific action is
             * necessary to poll the sensor. */
            wait(1);
            
            /* Set Score */
            scoreA = scoreA + 1;
            
            /* Updates the Eddystone URL Frame */
            ble.shutdown();
            delete eddyServicePtr;
            
            ble.init(bleInitComplete);
            while (ble.hasInitialized()  == false) { /* spin loop */ }
            
            triggerA = false;
            alivenessLED = false;
        }
        
        if (triggerB) {
            /* Do blocking calls or whatever hardware-specific action is
             * necessary to poll the sensor. */
            wait(1);
            
            /* Set Score */
            scoreB = scoreB + 1;
             
            /* Updates the Eddystone URL Frame */
            ble.shutdown();
            delete eddyServicePtr;
            
            ble.init(bleInitComplete);
            while (ble.hasInitialized()  == false) { /* spin loop */ }       
            
            triggerB = false;
            alivenessLED = false;
        }
        
        ble.waitForEvent(); /* this will return upon any system event (such as an interrupt or a ticker wakeup) */
    }
}