1

Short/summary

I expected that the round trip delay of a nRF24L01+ would be less than 1 ms. In practice I see around 3 to 5 ms and other sources have similar values. Does anybody know why this round trip delay is so long? In short: nRF24L01+, adapters for them, tmrh20 RF24 library, 16 byte payload, highest speed.

Below is the full problem and related info.

Problem description

I received my nRF24L01+ radios and they work much better so far than my 433 MHz radios.

However, still with my nRF24L01 I get response times which are much lower than I expected.

I used the sketch of Example using dynamic payloads (which I increased to 16). The library I use is from tmrh20.github.

I also reduced the characters written to serial (and increased it to 250K) and some other small changes.

Transmitter code

Below is the code for the transmitter (manually removed receiver code and role switching code since that works/was not used except for first time)

/*
   Dec 2014 - TMRh20 - Updated
   Derived from examples by J. Coliz <maniacbug@ymail.com>
   http://tmrh20.github.io/RF24/pingpair_ack_8ino-example.html

   Results:   
  PA                          MAX          
  Retries                    2,8   2,4   2,8   
  AutoAck                     True       False True
  EnableAckPayLoad            True
  PayLoadSize                  16          16    8   32
  DynamicPayLoad              True                        False True
  CRC Length                   16                                 8

  Failures / 25 iterations     0-1  3-4  ???         24??

  write min [us]              812    (792)    625         652   644
  write avg [us]              2618           2106              2251
  write max [us]              6224   (804)   5756        5756  7724

  logdata[m][n] = millis()       4                  us
  write:                       812..6224 (avg 2617) us
  available:                    28..  32            us
  read                         100                  us
*/
#include <SPI.h>
#include "RF24.h"

RF24 radio(7, 8);
uint32_t counter = 0;

static const int NR_OF_LOG_ITEMS = 10;
static const int LOG_LENGTH = 25;
uint32_t logData[LOG_LENGTH][NR_OF_LOG_ITEMS];
uint8_t currentLogLine = 0;

void setup()
{
  for (int m = 0; m < LOG_LENGTH; m++)
  {
    for (int n = 0; n < NR_OF_LOG_ITEMS; n++)
    {
      logData[m][n] = -1;
    }
  }

  Serial.begin(250000);
  Serial.println(F("TRANSMITTER SPEED TEST"));

  radio.begin();
  radio.setPALevel(RF24_PA_MAX);
  radio.setRetries(2, 8);
  radio.setAutoAck(true);
  radio.enableAckPayload();
  radio.setPayloadSize(16);
  radio.enableDynamicPayloads();
  radio.setCRCLength(RF24_CRC_16);

  byte addresses[][6] = {"1Node", "2Node"};
  radio.openWritingPipe(addresses[0]);
  radio.openReadingPipe(1, addresses[1]);
  radio.startListening();

  radio.writeAckPayload(1, &counter, 16);
  //radio.printDetails();
    radio.stopListening(); // Takes 336..348 us

}

uint32_t response = 0;

void loop(void)
{
  uint32_t response;

  uint32_t time = micros();
  logData[currentLogLine][1] = micros();

  if (radio.write(&counter, 16))
  {
    logData[currentLogLine][2] = micros();
    if (!radio.available()) 
    {
      logData[currentLogLine][3] = micros();
      Serial.print(F("Got blank response. round-trip delay: "));
      Serial.print(micros() - time);
      Serial.println(F(" microseconds"));
    }
    else
    {
      logData[currentLogLine][4] = micros();
      while (radio.available())
      {
        logData[currentLogLine][5] = micros();
        unsigned long timer = micros();
        radio.read(&response, 16);
        logData[currentLogLine][6] = micros();
        logData[currentLogLine][7] = response;
        logData[currentLogLine][8]++;
        Serial.print(F("Got response "));
        Serial.print(response);
        Serial.print(F(" round-trip delay: "));
        Serial.print(timer - time);
        Serial.println(F(" microseconds"));
        counter++;
      }
    }
  }
  else
  {
    logData[currentLogLine][9] = micros();
    Serial.println(F("Sending failed."));  // If no ack response, sending failed
  }

  if (counter == LOG_LENGTH)
  {
    for (int m = 0; m < LOG_LENGTH; m++)
    {
      Serial.print("Location ");
      Serial.print(m);
      Serial.print(": ");
      for (int n = 0; n < NR_OF_LOG_ITEMS; n++)
      {
        Serial.print(logData[m][n]);
        Serial.print("  ");
      }
      Serial.println("");
    }
  }
  currentLogLine++;

  delay(100);  // Try again later
}

Receiver code

Below is the code for the receiver (manually removed transmitter code and role switching code since that was not used)

/*
   Dec 2014 - TMRh20 - Updated
   Derived from examples by J. Coliz <maniacbug@ymail.com>
*/
#include <SPI.h>
#include "RF24.h"

RF24 radio(7, 8);
uint32_t counter = 0;

void setup() {

  Serial.begin(250000);
  Serial.println(F("RECEIVER SPEED TEST"));

  radio.begin();
  radio.setPALevel(RF24_PA_MAX);
  radio.setRetries(2, 8);
  radio.setAutoAck(true);
  radio.enableAckPayload();
  radio.setPayloadSize(16);
  radio.enableDynamicPayloads();
  radio.setCRCLength(RF24_CRC_16);

  byte addresses[][6] = {"1Node", "2Node"};
  radio.openWritingPipe(addresses[1]);
  radio.openReadingPipe(1, addresses[0]);
  radio.startListening();

  radio.writeAckPayload(1, &counter, 16);
  //radio.printDetails();
}

void loop(void)
{
  byte pipeNo = 0;
  uint32_t response = 0;
  while ( radio.available(&pipeNo))
  {
    radio.read( &response, 16);
    // Since this is a call-response. Respond directly with an ack payload.
    response++;
    radio.writeAckPayload(pipeNo, &response, 16); // This can be commented out to send empty payloads.
    Serial.print(F("Loaded next response "));
    Serial.println(response);
  }
}

Resulting log fragment

Below are the results:

TRANSMITTER SPEED TEST
Got response 26 round-trip delay: 1960 microseconds
Got response 1 round-trip delay: 1964 microseconds
Got response 2 round-trip delay: 876 microseconds
Got response 3 round-trip delay: 880 microseconds
Got response 4 round-trip delay: 1960 microseconds
Got response 5 round-trip delay: 4128 microseconds
Got response 6 round-trip delay: 6296 microseconds
Got response 7 round-trip delay: 880 microseconds
Got response 8 round-trip delay: 884 microseconds
Got response 9 round-trip delay: 3044 microseconds
Got response 10 round-trip delay: 880 microseconds
Got response 11 round-trip delay: 880 microseconds
Got response 12 round-trip delay: 884 microseconds
Got response 13 round-trip delay: 876 microseconds
Got response 14 round-trip delay: 1964 microseconds
Got response 15 round-trip delay: 1956 microseconds
Got response 16 round-trip delay: 4128 microseconds
Got response 17 round-trip delay: 3044 microseconds
Got response 18 round-trip delay: 4128 microseconds
Got response 19 round-trip delay: 1964 microseconds
Got response 20 round-trip delay: 4124 microseconds
Got response 21 round-trip delay: 8452 microseconds
Got response 22 round-trip delay: 880 microseconds
Got response 23 round-trip delay: 1960 microseconds
Got response 24 round-trip delay: 884 microseconds
Location 0: 4294967295  12328  14216  4294967295  14248  14280  14384  26  0  4294967295  
Location 1: 4294967295  115260  117152  4294967295  117184  117216  117316  1  0  4294967295  
Location 2: 4294967295  218152  218956  4294967295  218988  219020  219120  2  0  4294967295  
Location 3: 4294967295  319916  320728  4294967295  320760  320788  320888  3  0  4294967295  
Location 4: 4294967295  421684  423576  4294967295  423608  423636  423736  4  0  4294967295  
Location 5: 4294967295  524572  528628  4294967295  528660  528692  528792  5  0  4294967295  
Location 6: 4294967295  629624  635844  4294967295  635876  635912  636012  6  0  4294967295  
Location 7: 4294967295  736844  737660  4294967295  737688  737720  737820  7  0  4294967295  
Location 8: 4294967295  838616  839428  4294967295  839460  839492  839592  8  0  4294967295  
Location 9: 4294967295  940388  943364  4294967295  943396  943424  943524  9  0  4294967295  
Location 10: 4294967295  1044356  1045168  4294967295  1045200  1045232  1045332  10  0  4294967295  
Location 11: 4294967295  1146168  1146980  4294967295  1147012  1147040  1147140  11  0  4294967295  
Location 12: 4294967295  1247972  1248784  4294967295  1248816  1248848  1248948  12  0  4294967295  
Location 13: 4294967295  1349784  1350588  4294967295  1350620  1350652  1350756  13  0  4294967295  
Location 14: 4294967295  1451592  1453484  4294967295  1453516  1453548  1453648  14  0  4294967295  
Location 15: 4294967295  1554524  1556412  4294967295  1556440  1556472  1556580  15  0  4294967295  
Location 16: 4294967295  1657448  1661508  4294967295  1661536  1661568  1661668  16  0  4294967295  
Location 17: 4294967295  1762544  1765516  4294967295  1765548  1765580  1765680  17  0  4294967295  
Location 18: 4294967295  1866552  1870612  4294967295  1870640  1870672  1870772  18  0  4294967295  
Location 19: 4294967295  1971648  1973540  4294967295  1973572  1973604  1973704  19  0  4294967295  
Location 20: 4294967295  2074580  2078636  4294967295  2078668  2078696  2078804  20  0  4294967295  
Location 21: 4294967295  2179680  2188060  4294967295  2188092  2188124  2188224  21  0  4294967295  
Location 22: 4294967295  2289096  2289912  4294967295  2289940  2289972  2290072  22  0  4294967295  
Location 23: 4294967295  2390904  2392800  4294967295  2392832  2392860  2392960  23  0  4294967295  
Location 24: 4294967295  2493832  2494644  4294967295  2494676  2494708  2494808  24  0  4294967295

And here some processed (with Excel) results:

    write   available   available   read
    us  us  us  us
    1..2    2..4    4..5    5..6

    4060    32  28  100
    816 32  28  100
    6224    32  32  100
    2980    32  28  100
    1896    32  28  100
    816 32  32  100
    1896    32  32  100
    812 32  32  100
    2976    32  32  100
    2976    32  32  100
    816 28  32  100
    4060    32  32  100
    816 32  28  100
    4060    28  32  100
    816 32  32  100
    816 28  32  100
    1896    32  32  100
    5140    32  28  100
    6220    32  36  100
    816 32  32  100
    4060    32  32  100
    2980    28  32  100
    4060    32  28  100
    816 32  28  100

min     812 28  28  100
avg     2617.666667 31.33333333 30.83333333 100
max     6224    32  36  100

The main chunk is the write which takes 812..6224 us (with an average of 2617 us). Probably this big variance is due to retries, but still the lowest 812 us is more than expected:

Summary of results

I did some more tests, I will not put all log/intermediate results here, but the following table shows some tests:

  PA                          MAX          
  Restries                    2,8   2,4   2,8   
  AutoAck                     True       False True
  EnableAckPayLoad            True
  PayLoadSize                  16          16    8   32
  DynamicPayLoad              True                        False True
  CRC Length                   16                                 8

  Failures / 25 iterations     0-1  3-4  ???         24??

  write min [us]              812    (792)    625         652   644
  write avg [us]              2618           2106              2251
  write max [us]              6224   (804)   5756        5756  7724

  millis()  [us]                4
  available [us]              24/32
  read      [us]               100

Conclusion of results

  • Changing the number of retries lower than 2 (= 500 us), 8 (retries) results in too many errors, and does not lower the minimum, just the maximum, but with errors so useless
  • AutoAck always returns in 7u92-804 us, but I need AutoAck in my project
  • Changing payload to 8 results in a minimum of 625 us
  • Changing payload to 32 resulted in too many errors
  • Disabling dynamic payload resulted in a minimum of 652 us
  • Changing CRC length to 8 results in 644 us

Expectations

When I use the calculation in the datasheet, I come to the following results:

Datasheet  https://www.nordicsemi.com/eng/nordic/download_resource/8765/2/84238108/2726              
Table 15                
                Item                          Value Unit    Item              Value Unit  
T_OA            Time on-air                 0.0001005 s     Preamble              1 byte  
T_ACK           Time on-air Ack             0.0001005 s     Address               5 bytes 
T_UL            Time upload                 0.000512  s     Payload              16  bytes 
T_ESB           Time Enh Shock-Burst Cycle  0.0008785 s     CRC                   2 bytes 
Back and forth?                             0.001757  s     packet Control field  9 bits  
                                                            Air data rate   2000000 bits/s
                                                            SPI data rate    250000  bps  (guess)
                                                            T_stby2a        0.00013 s 
                                                            T_IRQ          0.000006  s 

According to the formulas, I would get around 0,875 ms (probably one way) and about double back-and-forth. Btw, I don't understand why T_OA is not in the formula.

However, I get as minimum 0,812 which may be some rounding/timing inaccuracy.

Conclusion

The retries are causing the longer writes. The minimum is similar to the calculated value from the datasheet.

Question

  • Home come there are so many retries?
  • Should I check for noise on channels?

Background

What I hoped for was to send a 32 (but 16 is ok too) byte message, than after 5 ms another message, and have the ack of the second message back within like 6 ms or so (including the 5 ms delay between the first and second message to be sent). This means the sending and receiving of an ack should take about 1 ms (which is well within the 0,256 ms calculated above).

Setup

Note my Uno's with nRF24L01 are about 1 meter apart, settings: 2 mbps, set retries(2, 4), enable ackpayload/dynamic payloads.

RF Radio hardware

The RF radios I'm using are nRF24L01+ like this:

nRF24L01+

Datasheet: PDF Download

Update: I see people use various capacitors and/or a voltage regulator. I did not do that, but I have a an adapter from 5V->3.3V specifically for the nRF24L01 (like this). I think there is already a voltage regulator and needed capacitors on this board. As far as I know the IC on the adapter is the voltage regulator and the capacitor (one) is probably just above the GND/VCC connection in the picture above. Or a second capacitor left of the MI/IRQ

Adapter

Results

  • 3
    You are not new here, so it should beyond obvious to you by now that this is unanswerable without your code. – Chris Stratton Jul 31 '17 at 3:22
  • 1
    Might want to check the actual frame size. There are a lot of "extra bits"; preamble, address, control, check-sum and there is also the PLL lock time to consider. Need a link to the manual :) – Mikael Patel Jul 31 '17 at 13:19
  • 1
    You might want to update the code so that the call to micros(), 32-bit calculation, number to string conversion and Serial print is included. Measure first-print after. – Mikael Patel Jul 31 '17 at 13:22
  • 1
    radio.enableAckPayload(); Disabling ack (or well, not enabling it) will improve the speed of transmission. – Avamander Jul 31 '17 at 21:17
  • 1
    Disable (or don't enable) dynamic payloads then? – Avamander Jul 31 '17 at 21:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.