The Arduino Nano 33 BLE Rev2 (Part: ABX00052) is a 3.3V, nRF52840-based microcontroller designed for Bluetooth Low Energy 5.0 applications. Unlike the original Rev1, the Rev2 updates the RF matching network and passive component layout to improve antenna efficiency and reduce sleep-mode current draw. If you are building a battery-powered sensor node, this board is the default pick for pure BLE projects, provided you navigate its Mbed OS stack and strict 3.3V logic limits.

Arduino Nano 33 BLE Rev2: The Decision Matrix

Arduino offers three similarly sized boards with wireless capabilities. Choosing the wrong one leads to unnecessary BOM costs or missing hardware accelerators. Use this decision tree to lock in your hardware selection before wiring.

Project Requirement Board Variant Part Number Verdict
Need pure BLE 5.0, lowest cost, and standard Nano footprint Nano 33 BLE Rev2 ABX00052 DEFAULT PICK. Best for custom sensor payloads and beacons.
Need onboard Gas (VOC), PM2.5, or 9-axis IMU telemetry Nano 33 BLE Sense Rev2 ABX00051 Choose this only if you need the BME688 or BMI270 without external breakouts.
Need WiFi (802.11 b/g/n) alongside BLE, plus hardware crypto Nano 33 IoT ABX00031 Choose this for MQTT-over-WiFi projects. BLE is secondary here (NINA-W102 module).
Pro-Tip: The Nano 33 BLE Rev2 operates strictly at 3.3V. Feeding 5V into any digital I/O pin will permanently damage the nRF52840 silicon. Always use logic level shifters if interfacing with 5V peripherals.

Hardware Specs and Pin Mapping

The Rev2 maintains external pin compatibility with the Rev1, but internal routing for the I2C pull-ups and power sequencing has been refined. Below is the critical specification sheet and pin mapping for standard sensor integration.

Parameter Specification
Microcontroller nRF52840 (Arm Cortex-M4 @ 64 MHz)
Operating Voltage 3.3V (Absolute max 3.6V on I/O)
Flash / SRAM 1 MB Flash / 256 KB SRAM
BLE Radio Bluetooth 5.0 (Cordio Stack via Mbed OS)
Deep Sleep Current ~15 µA (Rev2 optimized RF front-end)

I2C and Power Pin Mapping

Function Pin Label nRF52840 Port/Pin Notes
I2C SDA A4 P0.31 Internal 2.2k pull-ups enabled by default in Wire library.
I2C SCL A5 P0.29 Do not use external pull-ups unless >100kHz Fast Mode.
VIN VIN N/A Regulated input (4.5V - 21V). Bypasses 3.3V LDO if >4.5V.
3.3V Out 3V3 N/A Output from onboard MP2322 LDO. Max 800mA continuous.

Project Build: Low-Power BLE Sensor Beacon

We are building a BLE peripheral that reads temperature and humidity from an external BME280 and broadcasts it via a custom GATT service. This avoids the onboard PDM microphone and IMU to keep the current draw under 5mA average.

Parts List

  • MCU: Arduino Nano 33 BLE Rev2 (ABX00052)
  • Sensor: Adafruit BME280 I2C Breakout (Part: 2652)
  • Power: 3.7V 500mAh LiPo Battery (Adafruit 1578) with JST-PH 2.0 connector
  • Wiring: 4x M-F jumper wires (Silicone, 26 AWG)

Assembly Steps

  1. Prep the Power: Solder the JST-PH 2.0 pigtail to the LiPo if not pre-attached. Plug it into the white JST connector on the Nano 33 BLE Rev2. Verify polarity before plugging in.
  2. Wire I2C: Connect BME280 VIN to Nano 3V3. Connect BME280 GND to Nano GND. Connect BME280 SDI to Nano A4 (SDA). Connect BME280 SCK to Nano A5 (SCL).
  3. Address Check: The Adafruit 2652 breakout defaults to I2C address 0x77. If you are using a generic eBay/AliExpress BME280 module, it is likely 0x76. Note this for the code block below.

Complete Firmware: BLE Peripheral with Error Handling

This code targets the Arduino Nano 33 BLE Rev2 (ABX00052). It requires the ArduinoBLE and Adafruit BME280 Library installed via the Library Manager. Board package required: Arduino Mbed OS Nano Boards (version 4.0.8 or newer).

#include <ArduinoBLE.h>
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>

// --- PIN & ADDRESS DEFINITIONS ---
#define BME_I2C_ADDR 0x77 // Use 0x76 for generic breakouts
#define BLE_UPDATE_MS 2000

// --- BLE UUID DEFINITIONS ---
// Custom Service UUID
const char* SERVICE_UUID = "19B10000-E8F2-537E-4F6C-D104768A1214";
// Custom Characteristic UUIDs
const char* TEMP_UUID = "19B10001-E8F2-537E-4F6C-D104768A1214";
const char* HUM_UUID = "19B10002-E8F2-537E-4F6C-D104768A1214";

Adafruit_BME280 bme;

BLEService envService(SERVICE_UUID);
BLEFloatCharacteristic tempChar(TEMP_UUID, BLERead | BLENotify);
BLEFloatCharacteristic humChar(HUM_UUID, BLERead | BLENotify);

void setup() {
  Serial.begin(115200);
  // Wait for serial monitor to connect (optional, remove for deep sleep deployments)
  while (!Serial && millis() < 3000); 

  // 1. Initialize I2C and Sensor
  Wire.begin();
  if (!bme.begin(BME_I2C_ADDR, &Wire)) {
    Serial.println("FATAL: BME280 init failed. Check I2C wiring and address.");
    while (1) { delay(100); } // Halt execution
  }

  // 2. Initialize BLE Stack
  if (!BLE.begin()) {
    Serial.println("FATAL: BLE.begin() failed. Radio hardware fault or brownout.");
    while (1) { delay(100); }
  }

  // 3. Configure BLE Parameters
  BLE.setLocalName("Nano33-Env-Rev2");
  BLE.setAdvertisedService(envService);

  // Add characteristics to service
  envService.addCharacteristic(tempChar);
  envService.addCharacteristic(humChar);
  
  // Add service to BLE stack
  BLE.addService(envService);

  // Set initial values
  tempChar.writeValue(0.0);
  humChar.writeValue(0.0);

  // 4. Start Advertising
  if (!BLE.advertise()) {
    Serial.println("FATAL: BLE.advertise() failed. Stack memory limit exceeded.");
    while (1) { delay(100); }
  }

  Serial.println("BLE Peripheral is now advertising...");
}

void loop() {
  // Poll BLE events to maintain stack connection
  BLE.poll();

  // Read and broadcast sensor data
  float t = bme.readTemperature();
  float h = bme.readHumidity();

  // Update characteristics if a central is connected
  if (BLE.connected()) {
    tempChar.writeValue(t);
    humChar.writeValue(h);
  }

  delay(BLE_UPDATE_MS);
}

Debugging: First Three Checks and Exact Error Strings

The nRF52840 running Mbed OS is notoriously sensitive to power and stack memory limits. If your build fails, do not blindly rewrite code. Follow this exact diagnostic sequence.

The First Three Things to Check

  1. Board Package Core Version: Open Boards Manager and ensure Arduino Mbed OS Nano Boards is updated to at least v4.0.8. Older 2.x and 3.x releases had severe memory leaks in the Cordio BLE stack that cause random reboots after ~10 minutes of advertising.
  2. 3.3V Rail Sag Under TX Load: The nRF52840 pulls ~400mA peak current during BLE transmission bursts. If your LiPo has high Equivalent Series Resistance (ESR) or you are powering it from a weak USB hub, the voltage will sag below 3.0V, triggering a brownout reset. Measure the 3V3 pin with an oscilloscope; if you see dips below 3.1V during connection events, add a 470µF low-ESR tantalum capacitor across the 3V3 and GND pins.
  3. Phone BLE GATT Cache: iOS and Android aggressively cache BLE GATT tables. If you change a UUID or characteristic property in your code and re-flash, your phone will still look for the old structure and fail to connect. Fix: Toggle your phone's Bluetooth off and on, or use a dedicated BLE scanner app (like nRF Connect) and force-clear the device cache.

Exact Error Strings and Ranked Causes

Error String: FATAL: BLE.begin() failed.
  • Cause 1 (Most Likely): Power brownout during radio initialization. The RF front-end requires a stable 3.3V rail to calibrate the PLL. Check your power supply ESR.
  • Cause 2: Mbed OS thread collision. You have a blocking delay() or a heavy interrupt routine preventing the RTOS radio thread from spinning up. Move heavy processing out of ISRs.
  • Cause 3: Physical antenna damage or short circuit on the PCB trace preventing the radio chip from passing its internal POST (Power-On Self-Test).
Error String: FATAL: BLE.advertise() failed.
  • Cause 1 (Most Likely): Exceeded Cordio stack memory limits. You added too many characteristics, or your Local Name string exceeds the 29-byte BLE advertising payload limit. Shorten your BLE.setLocalName() string.
  • Cause 2: Invalid UUID formatting. Ensure your UUIDs are valid 128-bit hex strings. A missing character in the UUID string will cause the stack to reject the service registration silently, causing advertise() to fail downstream.

Extending and Simplifying the Build

Once the baseline beacon is stable, you must decide whether to optimize for battery life or feature density. Here is how to adjust the build based on your deployment constraints.

How to Simplify (For Ultra-Low Power)

If you need to run for months on a coin cell, strip the build down:

  • Drop the BME280: The external sensor draws ~1mA active. Use the nRF52840's internal die temperature sensor instead. It is less accurate (+/- 2°C) but draws zero external quiescent current.
  • Implement Deep Sleep: Replace the delay() in the loop with Mbed OS sleep functions. Use BLE.end() to shut down the radio entirely between hourly broadcasts, waking via the onboard RTC.

How to Extend (For Production IoT)

If this is a prototype for a commercial product:

  • Add DFU (Device Firmware Update): The nRF52840 supports over-the-air updates. Integrate the ArduinoOTA library alongside BLE to allow firmware patching without physical access to the USB port.
  • Add Security: Implement BLE bonding and AES-128 encryption. The ArduinoBLE library supports BLE.setSecurityLevel(). Set this to 2 (Encryption) or 3 (Authentication) to prevent unauthorized sniffing of your sensor payloads.

For detailed schematic references and Mbed OS core documentation, consult the official Arduino Nano 33 BLE Rev2 hardware docs and the ArduinoBLE library repository for the latest stack memory management updates.