First created: Aug, 2014 // Last updated: Aug, 2014
This project is inspired by Dmitry Grinberg’s idea “Bit-banging Bluetooth Low Energy”, which is hacking an nRF24L01+ module (which is under $1 per unit on eBay) as a low-cost Bluetooth Low Energy (BLE) advertizer. This can be used in various applications, such as sending small amount of insensitive data from a sensor to a smartphone, or things similar to iBeacon. Dmitry demonstrated the idea with a Nordic key fob which was retired by SparkFun, and the code was written for ATtiny24 microcontroller. What I intend to do here is to implement it on Arduino instead, layering the ground for other general purpose applications on Arduino. I also try to document the whole thing with more details. Luckily, it is not very hard after some research.
As Dmitry explained in his post, a “fake” BLE connection cannot be established between an nRF24 module (peripheral) and a BLE central device because of its hardware limitation. But BLE broadcasting from a nRF24 module is possible.
To understand how to fake BLE broadcasting with nRF24L01+, a comparison between the packet structure of BLE (Figure 1) and nRF24 (Figure 2) can be very helpful.
Figure 1: Advertizing packet structure of BLE.
BLE advertizing packet is made up of three sections:
Figure 2: nRF24 ShockBust(TM) packet structure. Note that there is no whitening as in BLE.
The nRF24L01+ actually has two different types of packet structures: ShockBurst and Enhanced ShockBurst. We want to use the old ShockBurst format, because the 9-bit packet control section between access address and payload in the Enhanced ShockBurst format makes it impossible for BLE fakery. From Figure 2, the packet format is similar to BLE, except that nRF24L01+ has 16-bit CRC rather than 24-bit, and there is no whitening. The way around is that we disable CRC on nRF24L01+ and compute it on our own; data whitening must be implemented in software as well. Also, for each packet section, nRF24L01+ transmits the most significant byte first, and also transmits the most significant bit first in each byte. This is just the opposite of BLE which transmits the least significant byte first with least significant bit first in each byte. So bit order reversal is required for access address and payload sections (preamble is automatically assembled based on the first bit in the access address).
The CRC-24 of BLE is implemented with linear feedback shift registers (LFSR) in hardware (Figure 3), which is the “btLeCrc()” function in the code (see the next section). It is a basic bit-by-bit manipulation (exclusive-or) to implement the modulo 2 division of 24-bit polynomials. Details of CRC can be found in the reference near the end of this article.
Figure 3: LFSR implementation of CRC-24 in BLE. The “dst” corresponds to the CRC buffer with the same name in the source code in the next section.
On the nRF24L01+ side, the pinout of the module is in Figure 4. It is relatively easy to operate with nRF24L01+ since both data transfer and configuration is carried out via SPI interface, by reading from and writing to the registers in nRF24L01+. Detailed information on how to use nRF24L01+ can be found in its datasheet. You are encouraged to go through the datasheet since it is not very long (less than 100 pages) and has everything you need to know.
Figure 4: nRF24L01+ module pinout.
You probably get nRF24L01+ modules with 4-by-2 headers, which cannot be directly mounted onto a breadboard. Here I solder a few wires to those headers to interface with a breadboard. The circuit is wired on breadboard as in Figure 5:
Figure 5: nRF24L01+ BLE broadcaster breadboarding.
The Arduino demo code can be found in my github repo here. After borrowing a few key functions from Dmitry’s code, it initializes nRF24L01+ with a few register writes, and then broadcasts with a device name “nRF24” and two bytes of custom data 0x0102 (for testing purchase) in BLE’s language. You can easily substitute the “0x0102” with other useful data such as an ADC reading from a sensor. Remember change the payload length and data container length accordingly to make the whole thing work.
After programming the Arduino, a BLE broadcaster named “nRF24” can be seen on my Android smartphone with BLE enabled. To view the custom data, I install the Android app “nRF Master Control Panel”, and I do see the “0x0102” custom data (Figure 6). Hooray!
Figure 6: nRF24L01+ BLE testing. Note that the custom data “0x0102” is recognized.