This RF ring oscillator runs on the NRF52 BLE SOC using the Adafruit feather development board. The NRF52 has an ARM Cortex M4F running at 64 MHz with built in BLE radio. This example uses a BLE stack provided by Adafruit. In particular, it makes use of the BLEUART service, a wrapper for the Nordic UART Service. On a host PC, we run a python script using the Adafruit BluefruitLE library.
To estimate round trip timing between two nodes, we time loops of the host program where a byte is sent to the slave, and the slave sends the byte back. We also time the loop (including the host transmission) without waiting for the response. In this way, we can subtract out the time taken by the host and estimate the time for a single RX and TX by the slave. The round trip packet time (as is consistent with other examples on this site) is then twice this estimate. In the graphs above, we average this estimate over 100 packets to get 84 milliseconds, or 168 milliseconds for the full round trip time.
An arduino sketch for the oscillator is available here, or visible below.
#include <bluefruit.h>
BLEDis bledis;
BLEUart bleuart;
uint8_t ch;
void setup()
{
Serial.begin(115200);
Serial.println("Bluefruit52 BLEUART Example");
Bluefruit.begin();
Bluefruit.setName("Bluefruit52");
Bluefruit.setConnectCallback(connect_callback);
Bluefruit.setDisconnectCallback(disconnect_callback);
// Configure and Start Device Information Service
bledis.setManufacturer("Adafruit Industries");
bledis.setModel("Bluefruit Feather52");
bledis.begin();
bleuart.begin(); // Configure and Start BLE Uart Service
setupAdv(); // Set up Advertising Packet
Bluefruit.Advertising.start(); // Start Advertising
while(1){
// echo BLEUART
if ( bleuart.available() )
{
ch = (uint8_t) bleuart.read();
bleuart.write(&ch,1);
}
}
}
void setupAdv(void)
{
Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
Bluefruit.Advertising.addTxPower();
// Include bleuart 128-bit uuid
Bluefruit.Advertising.addService(bleuart);
// There is no room for Name in Advertising packet, so use Scan response for Name
Bluefruit.ScanResponse.addName();
}
void loop(){}
void connect_callback(void) {Serial.println("Connected");}
void disconnect_callback(uint8_t reason)
{
(void) reason;
Serial.println();
Serial.println("Disconnected");
Serial.println("Bluefruit will start advertising again");
}
The python host script is available here, or visible below.
# Round trip timing of BLE UART Service
# Sam Calisch, 2017
# Adapted from Tony DiCola's BLE UART example: https://github.com/adafruit/Adafruit_Python_BluefruitLE
import Adafruit_BluefruitLE
from Adafruit_BluefruitLE.services import UART
import time
ble = Adafruit_BluefruitLE.get_provider()
def main():
ble.clear_cached_data()
adapter = ble.get_default_adapter()
adapter.power_on()
print('Using adapter: {0}'.format(adapter.name))
UART.disconnect_devices()
print('Searching for UART device...')
try:
adapter.start_scan()
device = UART.find_device()
if device is None:
raise RuntimeError('Failed to find UART device!')
finally:
adapter.stop_scan()
print('Connecting to device...')
device.connect()
try:
print('Discovering services...')
UART.discover(device)
uart = UART(device)
print "Measuring"
i = 0
N = 100
t0 = time.time();
times = []
#we run 2N trials
#the first N trials wait for a response from the ble uart
#the second N trials don't wait for a response, in order to time the host side of the loop
while(i<2*N):
uart.write("\n") #write newline to the TX characteristic.
received = uart.read(timeout_sec=10) if i<N else 10
if received is not None:
times.append( time.time()-t0 )
t0 = time.time()
i = i+1
finally:
device.disconnect() #disconnect on exit.
print "Disconnected"
print times
ble.initialize()
ble.run_mainloop_with(main)
Note: This test was run on a the Adafruit Feather Dev board, which uses the Raytac MDBT42Q module, incorporating the NRF52. The module retails for $7, the development board retails $24. Other modules are available for $5 from Fanstel.