Nano 33 ble nRF52840 - BLE long range/pairing ? Mbed BLE API ? Adafruit Lib?

Hi,

I recently bought the arduino nano 33 ble for a project. I chose this arduino board for 2 reasons :

  • I used arduino cards and the Arduino IDE in the past and found it accessible for beginners like me.
  • And I had difficulties finding other bluetooth 5 boards or modules that offer Long Range bluetooth.

Unfortunately, I found out that the libraries that go with the nano 33 ble (like ArduinoBLE) have very limited functionalities. For example, the Long Range bluetooth and the bluetooth pairing are missing whereas we see in the microcontroller's datasheet (nRF52840) that the hardware is compatible.

So I did some research in order to find other libraries or tricks to access to these features and I found some beginnings of solutions that I don't understand fully :

1- The nano 33 ble is based on mbed os that offers a BLE library (here) that is said to be less limited than ArduinoBLE. I found information on the Bluetooth pairing feature but a very few on the long range.
Also, when I wanted to try basic BLE API examples, I couldn't because even if we can import mbed functions in Arduino IDE using mbed::, the mbed examples aren't built like arduino's code (there is no setup() and loop()) and I found no tutorials on using mbed bLE library with arduino's code "style".
A solution of this would be to use mbed os IDE but it seems very complicated, needing to change the Bootloader (or something else i don't really understand) with a device like J-link that we must buy to make the board compile and upload.

2 - I found another library for the nRF52840 from Adafruit (here) that is also said to be less limited but still not much information on long range support. And it seems to need the same bootloader thing as mbed IDE to make the library work with the nano 33 ble.

3 - Using the datasheet, I tried to select the RADIO Long Range mode modifying registers with this command : "NRF_RADIO->MODE=5;" However, I doubt it is enough to really make it work knowing that if i don't want to recreate a whole library I still need to use ArduinoBLE that seems to be "interfering" with the command because it is switching back to basic BLE mode when I try combining both.

These are my questions :

Do you have information on how to use mbed BLE API in Arduino IDE and on the Long Range support ?

Is it worth doing the what's needed to use mbed os IDE or Adafruit Library ?

What parameters must I change using datasheet's registers to make Long Range work ?

Is there a way to combine these datasheet registers commands with the arduinoBLE library ?

Are there other ways to use the Long Range feature on the nano 33 BLE ?

Should I keep going finding solutions to use the nano 33 ble as I want or there are other boards/modules more adapted and easier to use (Which ones ?) ?

Thanks in advance.

I do have the very same problem and already contacted Arduino about it.
Sadly not yet any solution for this.

But hopefully there is anybody out who could look closer in this!?

Also I would love to hear what kind of boards are out as I need the function of a larger range. At least 200m. In my case even a raise in dB for RX for normal range could help.

Thank you for helping!

The issue if very likely the lack of support for Bluetooth 5 Long Range in phones, tablets and PCs. Arduino needs to make sure the features they release are supported well enough so most users have a good experience.

Just like every other company they need to manage the resources and probably have many other things they need and want to implement.

I totally disagree. This board is all about Bluetooth and features a chip that is used for long range BT and Bluetooth 5.
At least in normal settings a range of 200m is a must. And for long range or coded PHY 1000m.
It would help a lot if any of the RX settings could be changed.

Gernot1972:
I totally disagree.

I am just offering you a plausible explanation, why LR is currently not supported. I have been working in this industry for a little while.

Gernot1972:
This board is all about Bluetooth and features a chip that is used for long range BT and Bluetooth 5.

And this board can be used by amateurs and hobbyists, who can make use of most of the Bluetooth LE features without knowing a lot about radios. Which is amazing.

Gernot1972:
It would help a lot if any of the RX settings could be changed.

You could use the module manufacturers tools to implement your own firmware with all the features you need.

Modifying the radio parameters creates the risk of users using settings that are breaking the laws of their country e.g. using to much TX power or the system not working anymore with other products e.g. most smartphones that do not have BLE LR support at the moment. Because most Arduino users do not know all the rules and regulations, Arduino has setup a configuration that can be used without the need to know them.

If this is more than a hobby project, there are many other solutions available in the market that give you all the freedom and responsibility. You could look at Silicon Labs which have LR support, high power TX and very good RX sensitivity, but Simplicity Studio is a lot more powerful and complicated than Arduino IDE.

I would expect LR to be supported by Arduino in the long run, when more phones support it and demand for it gets high enough.

Thank you for the reply!

Maybe there is also a misunderstanding here. I am so disappointed of the power of the BT Module because all my project is not working because of this issue.
And in my case I do not "need" Long Range only 200m of range in plain sight.

The reason why I am so disappointed is that I previously tried the JBL charge4 speaker with Bluetooth 4.2 and reached about 400m and still could connect and play some sound on my iPhoneX.

So I thought because of BT5 is would be at least the same here.

How could I use other firmware?
In my project I already have a program that controls my servos connected to the Servo Control Adafruit Bonnet. And it is just a semi-professional use case here.

I like the module so far, but really need at least the power of BT4.2.
OK - Long range would be a "nice to have" but I am happy to connect in a 200m range.

I hope you could give me some more hint what I can do.
I also got in contact with arduino and I also hope that somebody is checking my issue right now.

Best regards

Same here !
I just bought 2 nano 33 BLE to perform remote measurements. One nano 33 BLE used as peripheral and the other nano 33 BLE used as central device.
Using the ArduinoBLE library, I am not able to reach more than 10-15 meters distance between both nano 33 BLE. I tried with other central (iPhone, Raspberry...) and the result is the same.
I guess LR is not configured at all by the library and I can not find a way to configure it. Help from arduino team required :slight_smile:

Now my fear is when I read the description of this forum "Nano 33 BLE - Designed for short range BT interactions and power savvy projects.". Does this mean that the nano 33 BLE is only designed for short range BT ? If yes, it must be clearly mentioned in the product description, I would not have bought it...

Steph92a:
Using the ArduinoBLE library, I am not able to reach more than 10-15 meters distance between both nano 33 BLE.

Please have a look at your PCB and make sure the green antenna area has 5 small components. There have been issues with some boards with distance as small as you mentioned and they had components missing on the antenna area of the BLE module.

Have a look at the following post. There is a test program I wrote and used for range testing as well as a picture of the PCB how it should look like.

https://forum.arduino.cc/index.php?topic=659562.0

Please have a look at your PCB and make sure the green antenna area has 5 small components.

The 5 small components are there on both my devices

Hello everyone,
thanks for all your answers, I have good news !

After a lot of research trying to understand how the mbed BLE API works, I discovered how to get long range by setting the PHY to CODED and the Radio TX output power to 8dbm. All of this is possible thanks to the mbed BLE library which can look complex at first for C++ beginners like me (it is more complex than ArduinoBLE though) but is actually very powerful and way more complete.

This is the code I made for the long range feature with which I reached a 200 meters range :

/*==============================================
DEMONSTRATION OF THE LONG RANGE FEATURE :

The Bluetooth is managed by a class ("LRDemo"). 
When an objet is created from this class, we
can call the .start() function. It will initialize
Bluetooth and once it's done, it will advertise
using PHY CODED technologie (= Long range) with
the max output power (8dbm). It will be connectable
and keep the long range mode during connection
however it won't have specifics services.

WORKING ON MBED 5 WITH ARDUINO NANO 33 BLE (NRF52840)
Library needed : BLE_API
Average Consumption : 1,20mA
================================================*/

/*--------INCLUDES--------*/
#include "ble/BLE.h"
/*------------------------*/

using namespace mbed;       // Enable us to call mbed functions without "mbed::"

/*------------GLOBAL VARIABLES-------------*/
const static char DEVICE_NAME[] = "LR Demo";                    // Device name when detected on Bluetooth
static events::EventQueue event_queue(10 * EVENTS_EVENT_SIZE);  // Create Event queue
static const uint16_t MAX_ADVERTISING_PAYLOAD_SIZE = 59;        // Advertising payload parameter
const ble::phy_set_t CodedPHY(ble::phy_t::LE_CODED);            // Creating a Coded Phy set
/*-----------------------------------------*/






/*------------------------------Bluetooth Device class------------------------------*/
class LRDemo : public ble::Gap::EventHandler {
public:
    /* Class constructor */
    LRDemo(BLE &ble, events::EventQueue &event_queue) :
        _ble(ble),                                      // BLE API Class
        _event_queue(event_queue),                    
        _adv_handle(ble::INVALID_ADVERTISING_HANDLE),   // Advertising parameter
        _adv_data_builder(_adv_buffer) { }              // Advertising parameter

    /* Class destructor */
    ~LRDemo() {
        if (_ble.hasInitialized()) {
            _ble.shutdown();
        }
    }

    void start() {
        _ble.gap().setEventHandler(this);               // Assign GAP events to this class
        _ble.init(this, &LRDemo::on_init_complete);     // Initialize Bluetooth
        _event_queue.dispatch_forever();                // Wait for event forever
    }

private:
    /** Callback triggered when the ble initialization process has finished */
    void on_init_complete(BLE::InitializationCompleteCallbackContext *params) {
        if (params->error != BLE_ERROR_NONE) {
            Serial.println("Ble initialization failed.");
            return;
        }
        Serial.println("Ble initialized.");

        /* Create advertising parameters and payload */
        ble::AdvertisingParameters adv_parameters(
            ble::advertising_type_t::CONNECTABLE_NON_SCANNABLE_UNDIRECTED,    // Advertising Type here : connectable non scannable undirected = connectable with exetended advertising
            ble::adv_interval_t(ble::millisecond_t(500)),           // Min Advertising time in ms
            ble::adv_interval_t(ble::millisecond_t(500)),           // Max Advertising time in ms
            false                                                   // Legacy PDU : Needed to be OFF in Long Range Mode
        );
        adv_parameters.setPhy(ble::phy_t::LE_CODED, ble::phy_t::LE_CODED);  // Set Advertising radio modulation to LE_CODED Phy (=Long Range)
        adv_parameters.setTxPower(8);                                       // Set radio output power to 8dbm (max) 
        _ble.gap().setPreferredPhys(&CodedPHY, &CodedPHY);                  // Set preferred connection phy to LE_CODED (=long range)

        if (_adv_handle == ble::INVALID_ADVERTISING_HANDLE) {       // Create advertising set with parameters defined before
        _ble.gap().createAdvertisingSet(
                &_adv_handle,
                adv_parameters);
        }
        _adv_data_builder.clear();                                  
        _adv_data_builder.setFlags();                                
        _adv_data_builder.setName(DEVICE_NAME);                     // Set Bluetooth device name

        /* Setup advertising */
        _ble.gap().setAdvertisingParameters(_adv_handle, adv_parameters); 
        _ble.gap().setAdvertisingPayload(_adv_handle, _adv_data_builder.getAdvertisingData());  

        /* Start advertising */
        _ble.gap().startAdvertising(_adv_handle);
        Serial.println("Start advertising...");
    }

    void onConnectionComplete(const ble::ConnectionCompleteEvent &event) {
        Serial.println("Device connected");
    }

    void onDisconnectionComplete(const ble::DisconnectionCompleteEvent&) {
        Serial.println("Device disconnected");
        _ble.gap().startAdvertising(_adv_handle);
        Serial.println("Start advertising...");
    }
    

private:
    /* Class variables declaration*/
    BLE &_ble;
    events::EventQueue &_event_queue;

    uint8_t _adv_buffer[MAX_ADVERTISING_PAYLOAD_SIZE];  // Advertising parameters
    ble::advertising_handle_t _adv_handle;              //
    ble::AdvertisingDataBuilder _adv_data_builder;      //
};
/*----------------------------------------------------------------------------------*/

/** Schedule processing of events from the BLE middleware in the event queue. */
void schedule_ble_events(BLE::OnEventsToProcessCallbackContext *context) {
    event_queue.call(Callback<void()>(&context->ble, &BLE::processEvents));
}

/*====================== MAIN CODE ======================*/

void setup(){
    /* Setup Debugging */
    Serial.begin(9600);
    while(!Serial);

    /* Low Power */
    digitalWrite(LED_PWR, LOW);                 // Turn off power LED
    digitalWrite(PIN_ENABLE_SENSORS_3V3, LOW);  // Turn off sensors
    NRF_POWER->DCDCEN = 0x00000001;             // Enable DCDC
    /*           */

    BLE &ble = BLE::Instance();                 // Create the BLE object in order to use BLE_API function
    ble.onEventsToProcess(schedule_ble_events); // Set event schedule

    LRDemo demo(ble, event_queue);              // Create LRDemo Object
    demo.start();                               // Start Bluetooth Long Range 
}

void loop(){}

/*=======================================================*/

It is based on the examples provided by the library (here). I advise you to look at these examples and at the documentation (here) to understand how the library works.

The Mbed BLE_API is included in the arduino nano 33 ble firmware so there is no need to install anything.
My code is also optimized for low power consumption (1.20mAh when powering from an external source).

Hope it helps ! I am here if there is any questions about the code.

4 Likes

Well done for persevering. That is excellent news.

As you've made the leap into mbed BLE and cracked the long range PHY challenge, are you going attempt pairing. Should be a breeze for you now.

Hello,

Colas71, thank you so much for the contribution. I am sure this will be extremely useful for the community.

Please be aware that the code did not compile with the latest core version (1.9.7). At the moment it compiles with the previous mbed version (1.9.6).

I hope this helps!

1 Like

Sounds a promising solution. But I just tried the code posted by Colas 71 on my arduino 33 BLE, and I do not see the peripheral (I use LightBlue on my iPhone).

Changing the advertising type to CONNECTABLE_UNDIRECTED make it visible in LightBlue, but the range seems very short as before (i.e. around 15m).

ble::advertising_type_t::CONNECTABLE_UNDIRECTED,    // Advertising Type here : connectable undirected = Cannot carry extended advertising payload, only legacy PDUs -- that may be the issue why long range does not work anymore
//ble::advertising_type_t::CONNECTABLE_NON_SCANNABLE_UNDIRECTED,    // Advertising Type here : connectable non scannable undirected = connectable with exetended advertising
1 Like

Steph92a:
Sounds a promising solution. But I just tried the code posted by Colas 71 on my arduino 33 BLE, and I do not see the peripheral (I use LightBlue on my iPhone).

Most phones do not support BLE long range.

Long range support is achieved at the PHY level. This means when the silicon does not have some special circuit for Forward-Error-correcting code (FEC) build into the radio PHY, the functionality cannot be added.

It looks like iPhone 11 with iOS 13.4 beta or newer could support BLE LR.

There could be some more phones in the market, I would look for flagship phones from the different manufacturers and then Google the specific phone name and "BLE long range" to see if somebody has tested this.

I have an iPhone XR that includes Bluetooth 5.0, is long range an optional feature of version 5.0 ?

Steph92a:
I have an iPhone XR that includes Bluetooth 5.0, is long range an optional feature of version 5.0 ?

Yes, the Bluetooth LE Coded PHY (125kBit (~4x range), 500kBit (~2x range)) and LE2M 2MBit (higher data rate but shorter range) are all optional features in Bluetooth 5.0.

I found some post where people believe iPhone XR could support LR. But that could just be a guess based on the fact that it supports BLE5. Additionally, the hardware might be able, but iOS might not support it on this phone.

Even if you have an iPhone 11 and iOS supports LR you might still not be able to use it unless you have an app that actively uses this feature. My guess is right now, there are no consumer end products on the market that use this feature. If I were Apple, I would enable the feature in the OS for apps that want to use it but otherwise the LR mode would stay switched off.

So, I recommend you look for indications that an app might support this feature and see if you can use that to test it. You can also look if you can find some app development information about this feature.

Very good job Colas71 and thanks your for your contribution.

I am not yet very comfortable with this Mbed BLE_API and the BLE. How can I add and assign a custum service with custom UUIDs and these characteristics.

Before your code I used ArduinoBLE.h

// BLE Battery Service
BLEService batteryService("180F");

// BLE Battery Level Characteristic
BLEUnsignedCharCharacteristic BatterieChar("2a19", BLERead | BLENotify); // remote clients will be able to get notifications if this characteristic changes
BLEUnsignedCharCharacteristic MouvementChar("2a20",BLERead | BLENotify); // remote clients will be able to get notifications if this characteristic changes
BLEUnsignedCharCharacteristic DetectionChar("2a21",BLERead | BLENotify); // remote clients will be able to get notifications if this characteristic changes
BLEUnsignedCharCharacteristic AlarmeChar("2a22",BLERead | BLENotify); // remote clients will be able to get notifications if this characteristic changes

BLE.setAdvertisedService(batteryService); // add the service UUID
batteryService.addCharacteristic(BatterieChar); // add the battery level characteristic
batteryService.addCharacteristic(MouvementChar);
batteryService.addCharacteristic(DetectionChar);
batteryService.addCharacteristic(AlarmeChar);
BLE.addService(batteryService); // Add the battery service
BatterieChar.writeValue(0); // set initial value for this characteristic

Thanks for your replies

pailhoux:
I am not yet very comfortable with this Mbed BLE_API and the BLE. How can I add and assign a custum service with custom UUIDs and these characteristics.

When you create your own services and characteristics you should use random 128-bit UUIDs. You can write a small script to generate them yourself or use a web tool (Google UUID generator).

16-bit UUIDs are assigned by the Bluetooth SIG and you should only use them when you implement a defined service or characteristic. You can look them up on the Bluetooth SIG web page.

Ok thanks.

But my question is : how I have to do for add one custum service called MYSERVICE for exemple and one or more int custum Characteric to this servie called for exemple MYCHARACTERIC1.
Using the Colas71 code.

Probably using methods of _adv_data_builder member of AdvertisingDataBuilder class but I don't find any exemple on the web and I unsucced by myself. :confused:

I found my solution here :

In addition there is a video. :wink: