Test Environment
The ideal test environment for over-the-air transmission testing would be a shielded anechoic RF chamber with an unobstructed signal path between antennas. For BLE, 10 meters is a reasonable test distance. When I was planning this project, I started a discussion about RF Transmission Testing Inside a Faraday Cage. Several responses suggested that I should try to find an outdoor environment like a park where I could get the benefit of unobstructed transmission distance and reduced rf noise and echo. Of course, all of these things are logistically difficult. Since my basic objective is to get performance comparisons between different development boards and configurations, I'm hoping that with a relatively clean short range setup that I'll be able to get repeatable and reproduceable results that will extrapolate to real life use cases.
I've settled on using the test bench in my workroom which will provide an unobstructed 2 meter separation (I could get 7 meters in the spare garage bay, so I may try a few measurements out there as a sanity check). The benefit of my workroom is that it is convenient to operate the setup remotely from the adjacent computer room. I want to avoid any proximity effects from being in the same room as the antennas.
Software configuration
I've explored two different software options to operate the development boards that I'm testing. The first is Direct Test Mode (DTM). Direct Test Mode is device specific firmware that implements a set of RF PHY test cases (transmitter and receiver) which are defined by the Bluetooth Special Interest Group (SIG) for product qualification testing. DTM is controlled by a host processor over a serial UART interface, so I would need to modify the firmware for each specific development board type. DTM allows interactively changing transmitter parameters like transmit power and transmit channel, so this would have been my preferred approach but I've had some difficulty getting it to work on boards that I am using. For the sake of demonstrating the FPC1500 capability in a timely manner, I've decided to take a second approach using an application program that has examples available for the BLE libraries for the various development boards types. That application program is iBeacon. iBeacon is a BLE advertising beacon developed by Apple and introduced in iOS 7.
Transmitter test requirements
For the purpose of the comparison tests, I have 4 basic requirements:
1) Periodically transmit a data stream
2) Have uniquely identifiable data for each device
3) Ability to set transmit power level
4) Ability to set transmit channel
iBeacon description
iBeacon functions in transmit only mode to send out advertisements that get discovered and utilized by other BLE-capable devices for location and proximity purposes.
iBeacon implements the following
1) Company identifier
2) Beacon UUID (device)
3) Major ID (region)
4) Minor ID (sub-region)
5) Advertising interval
6) Device name (optional)
7) Max advertising packet length (0x17)
So, the IBeacon application covers the first 2 of my test requirements and the power level and transmit channel can be set using parameters in the BLE library.
iBeacon limitations
1) Only uses BLE advertising channels (37,38,39)
2) Configuration is not dynamic - parameters are set at compile time
Unique Device identification (for device types tested)
Company (manufacturer identifier) - https://www.bluetooth.com/specifications/assigned-numbers/company-identifiers/
Company | Identifier |
Apple Inc | 0x004C |
Cypress Semiconductor | 0x0131 |
Espressif Incorporated | 0x02E5 |
Nordic Semiconductor SA | 0x0059 |
Random generated unique device UUIDs - https://www.uuidgenerator.net/
Program development example for the Sparkfun ESP32 Thing Plus iBeacon using the Arduino IDE with the ESP32 BLE Arduino library.
1) Start with BLE_iBeacon example
2) Modify Company and Device IDs (Device ID is BEACON_UUID)
3) Add settings for Transmit Power and Advertising Channel
4) Change the advertising interval from 10 seconds to 1 second (GPIO_DEEP_SLEEP_DURATION)
In order to determine functions and enum values to set the Transmit Power and Advertising Channel, I needed to examine specific BLE library that I am using for the ESP32.
From the Arduino IDE compile output: Using library BLE at version 2.0.0 in folder: C:\Users\Ralph\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.3\libraries\BLE.
For the advertising channel:
enum esp_ble_adv_channel_t
ADV_CHNL_37 = 0x01
ADV_CHNL_38 = 0x02
ADV_CHNL_39 = 0x04
ADV_CHNL_ALL = 0x07
setAdvertisementChannelMap(ADV_CHNL_37); // Default is ADV_CHNL_ALL
For the Transmit Power:
typedef enum {
ESP_PWR_LVL_N12 = 0, /*!< Corresponding to -12dbm */
ESP_PWR_LVL_N9 = 1, /*!< Corresponding to -9dbm */
ESP_PWR_LVL_N6 = 2, /*!< Corresponding to -6dbm */
ESP_PWR_LVL_N3 = 3, /*!< Corresponding to -3dbm */
ESP_PWR_LVL_N0 = 4, /*!< Corresponding to 0dbm */
ESP_PWR_LVL_P3 = 5, /*!< Corresponding to +3dbm */
ESP_PWR_LVL_P6 = 6, /*!< Corresponding to +6dbm */
ESP_PWR_LVL_P9 = 7, /*!< Corresponding to +9dbm */
} esp_power_level_t;
setPower(ESP_PWR_LVL_N0); // Default is 0dBm
ESP32_Thing_Plus_BLE_iBeacon_Single_Channel.ino
/*
Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleScan.cpp
BLE_iBeacon ported to Arduino ESP32 by pcbreflux
06/28/2022
Modified by Ralph Yamamoto for BLE Transmitter Testing (customized per development board type)
*/
/*
Create a BLE server that will send periodic iBeacon frames.
The design of creating the BLE server is:
1. Create a BLE Server
2. Create advertising data
3. Start advertising.
4. wait
5. Stop advertising.
6. deep sleep
*/
#include "sys/time.h"
#include "BLEDevice.h"
#include "BLEUtils.h"
#include "BLEBeacon.h"
#include "BLEAdvertising.h"
#include "esp_sleep.h"
#define GPIO_DEEP_SLEEP_DURATION 1 // sleep x seconds and then wake up was 10
RTC_DATA_ATTR static time_t last; // remember last boot in RTC Memory
RTC_DATA_ATTR static uint32_t bootcount; // remember number of boots in RTC Memory
#ifdef __cplusplus
extern "C" {
#endif
uint8_t temprature_sens_read();
//uint8_t g_phyFuns;
#ifdef __cplusplus
}
#endif
// See the following for generating UUIDs:
// https://www.uuidgenerator.net/
BLEAdvertising *pAdvertising;
struct timeval now;
#define BEACON_UUID "bd4bfb64-f756-11ec-b939-0242ac120002" // UUID 1 128-Bit (may use linux tool uuidgen or random numbers via https://www.uuidgenerator.net/)
void setBeacon() {
BLEBeacon oBeacon = BLEBeacon();
oBeacon.setManufacturerId(0x02E5); // fake Espressif LSB (ENDIAN_CHANGE_U16!)
oBeacon.setProximityUUID(BLEUUID(BEACON_UUID));
oBeacon.setMajor((bootcount & 0xFFFF0000) >> 16);
oBeacon.setMinor(bootcount&0xFFFF);
BLEAdvertisementData oAdvertisementData = BLEAdvertisementData();
BLEAdvertisementData oScanResponseData = BLEAdvertisementData();
oAdvertisementData.setFlags(0x04); // BR_EDR_NOT_SUPPORTED 0x04
std::string strServiceData = "";
strServiceData += (char)26; // Len
strServiceData += (char)0xFF; // Type
strServiceData += oBeacon.getData();
oAdvertisementData.addData(strServiceData);
// Set Advertising Channel
pAdvertising->setAdvertisementChannelMap(ADV_CHNL_37);
pAdvertising->setAdvertisementData(oAdvertisementData);
pAdvertising->setScanResponseData(oScanResponseData);
pAdvertising->setAdvertisementType(ADV_TYPE_NONCONN_IND);
}
void setup() {
Serial.begin(115200);
gettimeofday(&now, NULL);
Serial.printf("start ESP32 %d\n",bootcount++);
Serial.printf("deep sleep (%lds since last reset, %lds since last boot)\n",now.tv_sec,now.tv_sec-last);
last = now.tv_sec;
// Create the BLE Device
BLEDevice::init("");
// Set the transmit power
BLEDevice::setPower(ESP_PWR_LVL_N0); // 0dBm
pAdvertising = BLEDevice::getAdvertising();
setBeacon();
// Start advertising
pAdvertising->start();
Serial.println("Advertizing started...");
delay(100);
pAdvertising->stop();
Serial.printf("enter deep sleep\n");
esp_deep_sleep(1000000LL * GPIO_DEEP_SLEEP_DURATION);
Serial.printf("in deep sleep\n");
}
void loop() {
}
FPC1500 configuration for Direct Connection
My starting point to configure the FPC1500 was the R&S Application Card that I shared in the Getting Started Blog. I found that I needed to make some changes to accommodate my test procedure.
Changes to Test Configuration
- Reference Level - this is the most important change since with a Direct Connection I could overload the RF input with the -20 dBm level (also could exceed it with close proximity antennas and high transmit power level). Based on the highest power level programmable in the library (9 dBm) and the fact that I should have some cable loss in the setup, I'm going to set the Reference Level to +10 dBm for direct connect.
- Attenuator Tracking - the default is for the Attenuator to track the Reference Level with a Low Distortion setting, I changed it to Low Noise which is a lower attenuation setting
- I/Q Power Trigger Level - the User Manual suggests setting the Trigger Level 6 dBm lower than the expected signal level
- Frequency Deviation - the application example used 100 KHz, but that caused the Eye Diagram to go offscreen, so I changed this value to 250 KHz (which is the current BLE specification for 1 Mbps).
Eye Diagram with Frequency Deviation set to 100 KHz
Eye Diagram with Frequency Deviation set to 250 KHz
Key sequence to configure FPC1500
1) Preset [Default Preset Mode]
2) Mode -> Digital Demod
3) Freq -> Center Frequency -> 2.402 GHz [default is 1.5 GHz]
4) Ampt -> Attenuator -> Auto Low Noise (Attenuator will track Reference Level) [default is Auto Low Distortion]
5) Ampt -> Reference Level -> +10 dBm for direct connection, -20 dBm for antennas
6) Sweep -> Trigger -> I/Q Power -> set 6 dBm below expected power level [default is Free Run, Continuous Sweep]
7) Meas -> FSK
8) Meas -> Standard -> Bluetooth LE (this also sets values shown with * below)
9) Meas -> Demod Parameters -> Frequency Deviation -> 250 kHz* [default is 100kHz]
10) Meas -> Demod Parameters -> Burst Processing [default is off]
11) Meas -> Number of Symbols -> 400* [default is 100]
12) Meas -> Filter Type -> Gaussian* [default]
13) Meas -> Symbol Rate -> 1 MHz* [default is 10kHz]
14) Meas -> Alpha/BT -> 0.5* [default is 1]
Measurement displays available in Digital Demod Mode
1) Eye Diagram
2) Symbols
3) Modulation Deviation
4) Modulation Error
I am going to create my own User Defined Presets to use instead of the Default when I am satisfied with the configurations.
Direct Connection Test Setup with ESP32 Thing Plus
FPC1500 Configuration
I/Q Power Trigger Level Test
I've noticed in a lot of my eye diagrams that there are often spurious traces in the eye, as if the burst did not get synchronized correctly. And I noticed that when that occurs that the error numbers also get larger. I assumed that it was periodic RF noise and that it would not occur when I was directly connected. When the instrument triggers it gives me a Carrier Power measurement and my initial strategy was to set the I/Q Power Trigger Level 6 dBm below that value. However, I observed when testing the trigger level that I get the cleanest eye and lowest error rate when the trigger level is slightly (0.5 to 1 dBm) above the Carrier Power measurement. With the direct connection and my current device program I am getting Carrier Power between 1 to 1.5 dBm. The video below shows that effect.
I need to play with the software configuration a bit more and try some antenna measurements. Then, the next step will be to try to program the same settings on a Nordic nRF device and see how that compares.