I am very new to this domain, and I am facing some problems putting my nRF52840 Sense board into deep sleep and waking it up again. I have tried different code snippets from various sources, but my problem is still not resolved. I want to implement a very simple system in which pressing a push button for 3 seconds puts the board into deep sleep mode, indicated by the red LED blinking twice. Then, when in deep sleep, pressing the same push button for 3 seconds (if timing is not possible in deep sleep, a double-tap is acceptable) should wake the board up, indicated by the blue LED blinking twice.
I am using the non-Mbed BSP, version 1.1.10. The code I am currently using somewhat performs the desired behavior, but not as expected. When I press the button for 3 seconds, the red LED blinks twice, and the blue LED (which was continuously blinking as part of the BLE function) stops blinking and stays lit. When I press the push button again for 3 seconds, the red LED blinks twice again, and only then does the board enter deep sleep.
Ideally, when the board is in deep sleep, pressing the push button for 3 seconds should wake it up, but that doesn’t happen. I have to press the onboard reset button to activate the board. Please help me fix this issue. I have included the code I am currently using below:
#include <bluefruit.h>
#include <LSM6DS3.h>
#include <Wire.h>
#include <Air_mouse_gesture_complete_inferencing.h> // Edge Impulse model
#include <nrf.h>
#include “nrf_nvic.h”
#include “nrf_soc.h”
// ---- Pin Definitions ----
#define BUTTON_PIN 0 // D0 (used for deep sleep wake-up)
#define SAMPLE_INTERVAL_MS 10
#define CONFIDENCE_THRESHOLD 0.7
// IMU and BLE
LSM6DS3 imu(I2C_MODE, 0x6A);
BLEUart bleuart;
// Normalization
const float MEANS = {-0.3726, -0.6139, -0.1795, 7.1494, -4.6447, 2.9262};
const float STD_DEVS = { 0.708, 0.5731, 0.6498, 148.9435, 214.0082, 130.2576};
float features[EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE];
size_t feature_ix = 0;
// Button handling
unsigned long last_sample_time = 0;
unsigned long buttonPressStart = 0;
bool buttonHeld = false;
bool isSleeping = false;
// LED blink helper
void blinkLED(int pin, int times, int duration_ms) {
pinMode(pin, OUTPUT);
for (int i = 0; i < times; i++) {
digitalWrite(pin, LOW); // ON (active LOW)
delay(duration_ms);
digitalWrite(pin, HIGH); // OFF
delay(duration_ms);
}
}
// Normalize IMU data
float normalize(float x, float mean, float stddev) {
return (x - mean) / stddev;
}
// BLE chunked transmission
void bleuart_send_block(String &data) {
int len = data.length();
for (int i = 0; i < len; i += 20) {
bleuart.write((const uint8_t*)(data.c_str() + i), min(20, len - i));
delay(5);
}
}
// Initialize BLE
void initBLE() {
Bluefruit.begin();
Bluefruit.setTxPower(4);
Bluefruit.setName(“XIAO_Inference”);
bleuart.begin();
Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
Bluefruit.Advertising.addTxPower();
Bluefruit.Advertising.addName();
Bluefruit.Advertising.addService(bleuart);
Bluefruit.Advertising.restartOnDisconnect(true);
Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms
Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
Bluefruit.Advertising.start();
}
// Deep sleep
void goToDeepSleep() {
Serial.println(“Going to deep sleep…”);
blinkLED(LED_RED, 2, 200); // Red LED blink
// Ensure LEDs off
digitalWrite(LED_RED, HIGH);
digitalWrite(LED_BLUE, HIGH);
delay(50);
// Disconnect and stop BLE
Bluefruit.Advertising.stop();
Bluefruit.disconnect(0);
delay(100);
// Fully disable SoftDevice (BLE)
sd_softdevice_disable();
delay(50);
// Configure wake-up button
pinMode(BUTTON_PIN, INPUT_PULLUP_SENSE); // Use PULLUP_SENSE for wake-up
NRF_P0->PIN_CNF[BUTTON_PIN] = (GPIO_PIN_CNF_SENSE_Low << GPIO_PIN_CNF_SENSE_Pos);
// Enable wake-up on button press
sd_power_system_off();
}
// Setup
void setup() {
// Enable DC-DC for stable battery power
NRF_POWER->DCDCEN = 1;
// Initialize serial safely (no blocking)
Serial.begin(115200);
delay(100); // Replace while(!Serial) to avoid USB dependency
pinMode(BUTTON_PIN, INPUT_PULLUP);
pinMode(LED_RED, OUTPUT);
pinMode(LED_BLUE, OUTPUT);
digitalWrite(LED_RED, HIGH);
digitalWrite(LED_BLUE, HIGH);
// Check if we’re waking from sleep
if (NRF_POWER->RESETREAS & POWER_RESETREAS_OFF_Msk) {
// Clear the reset reason
NRF_POWER->RESETREAS = POWER_RESETREAS_OFF_Msk;
isSleeping = false;
blinkLED(LED_BLUE, 2, 200); // BLUE LED blink on wake
}
// IMU
if (imu.begin() != 0) {
Serial.println(“IMU failed”);
while (1);
}
// Initialize BLE
initBLE();
Serial.println(“Device ready”);
}
// Loop
void loop() {
// — Button check for deep sleep toggle —
int buttonState = digitalRead(BUTTON_PIN);
unsigned long currentMillis = millis();
if (buttonState == LOW) {
if (!buttonHeld) {
buttonHeld = true;
buttonPressStart = currentMillis;
} else if (currentMillis - buttonPressStart >= 2000) {
goToDeepSleep();
// After waking from sleep, we’ll start fresh in setup()
}
} else {
buttonHeld = false;
}
// — IMU Sampling & Inference —
if (millis() - last_sample_time >= SAMPLE_INTERVAL_MS) {
last_sample_time = millis();
float ax = imu.readFloatAccelX();
float ay = imu.readFloatAccelY();
float az = imu.readFloatAccelZ();
float gx = imu.readFloatGyroX();
float gy = imu.readFloatGyroY();
float gz = imu.readFloatGyroZ();
features[feature_ix++] = normalize(ax, MEANS[0], STD_DEVS[0]);
features[feature_ix++] = normalize(ay, MEANS[1], STD_DEVS[1]);
features[feature_ix++] = normalize(az, MEANS[2], STD_DEVS[2]);
features[feature_ix++] = normalize(gx, MEANS[3], STD_DEVS[3]);
features[feature_ix++] = normalize(gy, MEANS[4], STD_DEVS[4]);
features[feature_ix++] = normalize(gz, MEANS[5], STD_DEVS[5]);
if (feature_ix >= EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE) {
ei_impulse_result_t result;
signal_t signal;
if (numpy::signal_from_buffer(features, EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE, &signal) == 0) {
if (run_classifier(&signal, &result, false) == EI_IMPULSE_OK) {
if (bleuart.notifyEnabled()) {
String topLabel = "";
float topValue = 0.0;
for (size_t ix = 0; ix < EI_CLASSIFIER_LABEL_COUNT; ix++) {
float val = result.classification[ix].value;
if (val > topValue) {
topValue = val;
topLabel = result.classification[ix].label;
}
}
if (topValue > CONFIDENCE_THRESHOLD) {
String resultStr = topLabel + ": " + String(topValue, 5);
bleuart_send_block(resultStr);
}
}
}
}
feature_ix = 0;
}
}
}