Showing posts with label data. Show all posts
Showing posts with label data. Show all posts

Tuesday

 Arduino: Using the full potential of NRF24L01 radio modules
A New, Optimized Fork of the RF24 Radio Library: High speed data transfers and more!
Includes updates and new features for the RF24Network Library

Updated Jan 2015
  NRF24L01+ radio modules are very inexpensive, and provide a robust interface for transferring data wirelessly between devices with minimal resource and power consumption. I've been working with them more and more as time goes on, but have always struggled with some of the inner workings and limitations of the current libraries available.

After initially studying the operation of the radio modules and reviewing the details in the data sheet, I was convinced that the modules could perform much faster. Further research into the additional library forks, blog posts, and countless hours of testing revealed that the modules can be very sensitive to the timing of things. I also discovered a number of bugs and/or issues that would hinder performance and/or reliability. 

Initial testing proved very fruitful, with speeds maxing out the configured data-rate of the chip, and reliability was improved over previous iterations of the library. Over the course of the following year, the library has been further optimized and extended, with many new features, bug-fixes, and improved reliability and performance.

(See bottom of page for download links and documentation)

Taking Advantage of the Improvements:

From a user perspective, very little is changed from previous forks/libraries beyond the usage of the available() function. This is the main compatibility difference between this and the previous libraries. The available() function will always return 1 if data is available, to align the library with standard Arduino functions. From a technical perspective, the improvements are dramatic.

 Users will benefit from the improvements just by using the new library with old code, and some things not previously possible, can now be achieved. The included .ino examples have been configured to demonstrate 'standard' usage, but advanced users can still drive the chip outside the 'manufacturer recommended operation'

Additional functions have been added to aid in streaming or rapid-transmission situations, where 2 or more payloads are sent in rapid succession, or streamed at a high transfer rate. These include writeFast, writeBlocking, and txStandby. Use of these functions allow users to maximize throughput without overrunning the FIFO buffers. See the documentation for more info on usage. 


The addressing format has been extended to allow the use of 24,32 or 40-bit addresses, as well as defining and handling of addresses via byte arrays or integers.

For example, the following addresses are the same, and either format can be used:

uint64_t myAddress = 0x68524d5431LL;   ( Old Format   )
uint64_t myAddresses[] = { 0x68524d5431LL, 0x68524d5432LL};

byte myAddress[] = "1TMRh";                    ( New Format )
byte myAddress[] = {'1','T','M','R','h'};
byte myAddresses[][6] = {"1TMRh","2TMRh"};

Technical Info:
One of the primary factors in increasing efficiency was eliminating power ups and power downs from the general operation of the radio, which many of the existing forks already had identified. A power up takes 1.5ms or 1500us, where a transition from standby-I or standby-ii takes only 130us. In addition, leaving the CE pin high while data is written allows the possibility to have 0 delay if the TX FIFO buffer is kept busy, which this library makes use of via the writeFast() and writeBlocking() features.

This changes the operation of the radio a little bit, in that the radio needs to be powered up or powered down manually, instead of being powered down after every write.

The radio modules have shown to be very sensitive to the timing and order of operations, and many hours of testing and review have determined the optimal settings and order of operations to achieve the highest speed and reliability. Delays have been removed where possible, added where required, and minimized in every case.

As mentioned, the the available() and isAckPayloadAvailable() functions now simply check the FIFO buffer to see if a payload is available. This allowed simplification of the write() function, and should help to ensure that no packets are missed. Previous iterations used the interrupt flag, which can result in a number of issues.

The overall change in response is apparent when running example sketches like the GettingStarted_CallResponse sketch included with the library or the Transfer examples.

At this point, there are so many changes, bugfixes and details, it is best to see GitHub for all of the changes and technical info.

RF24Network: The standard RF24Network library has been updated to support the new changes, and a DEV version has implemented many new features like fragmentation/reassembly and multicast. This library is recommended if connecting any number of nodes, and provides addressing, routing, etc to help manage data in a network configuration. RF24Mesh is an overlay for RF24Network that provides automatic addrressing, and a dynamic topology for nodes running RF24Network and/or RF24Ethernet.

RF24Mesh: Automates addressing etc. for RF24Network and provides a seamless, self-healing network on top of all the layer 3 network features. 

RF24Ethernet adds a surprising level of reliability, consistency, and ease of use to nodes running RF24Network, by using standard TCP/IP networking. It uses the nrf24l01 radios as a standard Network Interface Card (NIC). It uses a Rasberry Pi or other Linux platforms as a network gateway, to allow RF24Network nodes to connect directly to web services or act as a web-server etc. Allows users to control nrf24l01 sensors or systems easily, reliably, and simply using any device with a web-browser, MQTT, etc. The API is very similar to the standard Arduino Ethernet library.

Class documentation now available here

Testing & Results:
Testing is now fully automated, with the introduction of TCP/IP support, with standard networking tools being used to test transfer speeds and reliability. Users can easily make use of the full data-rate in no-ack mode, full-duplex communication at 1MBPS with Ack-Payloads, or half-rate if using Enhanced ShockBurst (ESB). This has allowed many improvements to related libraries like RF24Network as well as the low level RF24 radio driver.

Since the initial release, many users including previous RF24 contributors have adopted the new library and provided feedback towards further improvements .See here for a demo of the initial transfer rate testing.
 
The wireless audio sketch/library that inspired these improvements is now linked below. The audio library itself is limited to around 16-20khz sample rate, which produces very reasonable sound quality for voice transmission. The limitation is due to the use of interrupts for virtually every part of the library, however, this makes it very simple to configure and use. See here for the development sketch, which was used to design the library, and is capable of higher quality audio. The wireless audio portion of the TMRpcm library has been updated to allow audio streaming and multicasting directly from SD card over RF24 modules as well.

New:
See the new store for reliable RF24 hardware and kits.

Reference Material/Libraries:

Raspberry Pi Simple Library Installer:
http://tmrh20.github.io/RF24Installer/RPi/install.sh

RF24 - Low Level Radio Driver (Generally used for device-to-device communication)
TMRh20 RF24 Fork on GitHub  - Download
RF24 Documentation 

RF24Network (Provides addressing, routing and many other features for use with multiple devices)
TMRh20 RF24Network Fork on GitHub - Download 

RF24Mesh (Dynamic 'mesh' layer for RF24Network)
RF24Mesh on GitHub - Download
Documentation

RF24Ethernet (Modelled after Arduino Ethernet API - TCP/IP over RF24Network)
RF24Ethernet on Github - Download
Documentation

RF24Audio (Digital Audio over RF24 radio modules)
RF24Audio Library

MySensors.org - Create user friendly sensor networks using RF24 radio modules

Alternative: RadioHead NRF24 Library - (Supports multiple radio devices)

NRF24L01 Data sheet
Original/Old RF24 Library by ManiacBug





Digital Data Encoding: Manchester, BMC and Frequency Modulation(FM)

Data generally needs to be encoded to enable the transmission of digital data across various mediums, and I've always had an interest in radio/wireless communication, so this was pretty much going to happen eventually. I've used some VirtualWire modules, and took an interest in how they work and how to apply the concepts learned from that code and other sources. This lead to the following sketches which encode data using a modified version of Biphase Mark Code (BMC) encoding, which is a specific form of Frequency Modulation, (FM) used to transfer digital data.


A Quick Look at BMC Encoding:

If you look up Biphase Mark Code online, you may be lead to information on Differential Manchester encoding, which has fundamental differences from BMC. You will also generally find excessively complex explanations of how it works, but it is actually quite simple. In the end, you basically send a bunch of binary data (1 and 0), and represent that data either with 1 long period or 2 short periods:

ie: 1 = Long, 0 = short,short  OR  0 = Long, 1 = short,short

The important factor is the length of time between transitions (The point at which the wave transitions from high to low or low to high). This image from wikipedia shows how the data is encoded into a wave:



How does it work?

This code is derived from concepts described here and in the VirtualWire Arduino library. The VirtualWire library appears to use a sampling based decode method and '4-to-6 bit' encoding of the data prior to transmission. Comparativly this was more of a learning exercise than a useful project, so is fairly simple, and uses timer based encoding.

Arduino Uno,Mega etc have an 'Input Capture' function that can trigger an interrupt and timestamp it, and I was interested in trying it out for this type of digital communication. This code uses that capability to calculate the difference between transitions and thus decode the binary data. Timer1 is used as a counter to provide the timestamp for the receiver, and used to generate the proper waveform for the transmitter.


Results:

I started off initially using Differential Manchester encoding, and was able to acheive ok results for wireless transmission. The results weren't very useable initially, so I tested a few different methods of modulation, ending up with BMC encoding producing the best results. BMC uses two small transitions for one bit, and one large for the other (0 or 1), so I tried it with only a single small transition, and seem to have the best results so far. I'm not sure if this fits in with another modulation technique, but it is FM either way.

Transmitter:

The data being sent is broken into bits and buffered into memory, while Timer1 is configured to run at a set frequency. A full pulse width is created to encode a 0, and a half pulse width is created to encode a 1, modulating the frequency to send data. The compare-output mode is toggled every cycle to produce the correct waveform, ensuring that positve pulses always follow negative pulses and vice-versa. 

Receiver:

The receiver uses the built-in Input Capture mode to timestamp the high and low transitions of the pulses being received, then calculates whether a 0 or 1 was received based on the timestamp. As the bits are received, they are loaded into a temporary byte. If that byte is equal to the 'start byte', it starts buffering data and looks for a 'stop byte'. Once received, it does a simple CRC check to ensure the data is not corrupt, and then makes the data available if successful.


Arduino Sketches:

 This seems to work well in testing, up to 32Kbps with a direct connection, and up to 7Kbps at close range with some very cheap 433Mhz VirtualWire capable modules I had sitting around. This was a pretty interesting task, and a good way to understand the general concepts behind the raw signaling that digital devices use to communicate. This is about as far as I plan to take this code for now, so I threw in a bunch of comment  s:

RX (receiver)  (Timer4, Pin 49 on Mega)
TX (transmitter) (Timer1, Pin9 on Uno,Nano,etc)


My Custom Zephyr + Arduino Build for Arduino Uno Q: Adding Zephyr Networking to the Mix

 My Custom Zephyr + Arduino Build for Arduino Uno Q: Adding Zephyr Networking to the Mix Using RF24Ethernet with native Zephyr networking  F...