NRF24L01: getARC maxes at 5

I am seeking advice on the retry function of the NRF24 library and why it apparently quits after 5 tries.

I am transferring sensor data using nRF24L01 transceivers

  • between a lipo driven Arduino Pro mini with soil moisture sensor
  • and a Wemos D1 mini "hub".
    TX is powered from 3.3 V pin with a 10uF cap and sleeps most of the time.
    Sketch includes RF24 and RF24network libraries.

Everything works except:

Reception is inconsistent. With one transmission every 3 hours I don't want to miss any.
So I am looking at the number of automatic retries with getARC().

Even with retries set to 15 (max), getARC() shows a maximum of 5 retries before failing.
(I am sending two transmissions in short succession so that the 2nd will show me the # of retries of the first.)

Is there a simple explanation why getARC() shows a maximum of 5 tries before fail even though # of retries is set to 15?

Thank you for your help.

Without seeing your programs it is impossible to comment.

See How to get the best out of the Forum

Simple nRF24L01+ Tutorial

I am sending two transmissions in short succession

From the getARC() reference:

Value resets with each new transmission.

What is a short succession? Is it long enough for 15 retries?

Without seeing your programs it is impossible to comment.

See How to get the best out of the Forum

Simple nRF24L01+ Tutorial

I will post the codes tomorrow, can‘t get to them right now. I sort of expected the question but thought there might be an obvious answer.

From the getARC() reference:

Value resets with each new transmission.

What is a short succession? Is it long enough for 15 retries?

I had the same effect posting once every 8 seconds (watchdog, sleep). I tried inserting delays to no avail. But I will run the sketch without it going to sleep and using a pause without delay to see if that makes a difference. I‘ll update tomorrow.

In the meantime, I have

  • run the sketch without powering up and powering down the radio in the send_data function (no effect)
  • inactivated the sleep commands and run the 3 functions in loop with a millis-based delay (no effect)
  • increased the delay between retries (no effect)

Here is the TX code:

#include <RF24Network.h>
#include <RF24.h>
#include <SPI.h>
#include <LowPower.h>

#define CE_PIN   9
#define CSN_PIN 10

const byte FS_pipe[5] = {'R', 'x', 'A', 'A', 'A'}; // pipe - same for RX and TX

RF24 radio (CE_PIN, CSN_PIN);           //create RF24 object called transmit

int BatPin = 0;                         //A0 pin to read battery voltage
int mapmax = 3399;
int SensorPin = 1;                      //A1 pin to read sensor
int fs_batValue = 0;

int lowValue = 370;                     // lower fs mapping limit
int highValue = 840;                    // upper fs mapping limit

uint8_t fs_bat = 0;                     //values for payload
uint8_t fs_bat_map = 0;
uint8_t fs_sen_map = 0;

uint8_t retries = 0;                    // variable to hold arc

const int numReadings = 3;              // average a few readings
int readings[numReadings];              // array of readings from analog input
int readIndex = 0;                      // the index of the current reading
int total = 0;                          // the running total
int average = 0;                        // the average
int warmup = 200;                       // delay to let sensor warm up

uint16_t sleepMin = 1;                // 180 - how many minutes to sleep
uint16_t i = 0;                         // counter for sleep cycles
float multi = 1;                        // (7) multiplier to arrive at minute value
bool ok = true;                         // check for successful TX

const unsigned long interval = 2000;    // delay for debug messages
unsigned long currentMillis;
unsigned long startMillis;

const uint16_t hub_node = 00;           // Address of hub
const uint16_t fs_node  = 01;           // Address of soil sensor
const uint16_t dht_node = 02;           // Address of this node

RF24Network network (radio);            //include the radio in the network

typedef struct payload {                // payload identical to DHT TX
  uint8_t fs_sen_map;                   // mapped sensor value
  uint8_t fs_bat_map;                   // mappd bat value
  uint8_t d_temp;                       // d-values come from dht_node
  uint8_t d_hum;
  uint8_t d_bat_map;
  uint8_t retries;                      // retries
} data;

void setup()
  pinMode(3, OUTPUT);                 // set D3 to power sensor

  while (!Serial) { }
  Serial.println("\nFS Transmitter Started");

  radio.setPALevel(RF24_PA_MIN);       // MIN, LOW, (MED not implemented), HIGH, (MAX)
  radio.setRetries(0, 15);             // delay x 250us, how many; both max 15
  radio.setCRCLength(RF24_CRC_8);       // Cyclic redundancy check
  radio.openWritingPipe(FS_pipe);       // open pipe
  radio.stopListening();                // set mode to transmitter

void loop() {


  readVcc();                            // get batvalue first to supply to FSread
  FSread();                             // read the sensor and map data
  send_data();                          // send the data

  /*Serial.println("Battery reading: ");
    Serial.print (fs_batValue);
    Serial.print ("mv  -  ");
    Serial.print (fs_bat_map);
    Serial.println ("%");
    Serial.println(" ");

    Serial.print("Mapped Average: ");

  Serial.println("-----------going to sleep----------\n");

  while (i <= (sleepMin * multi)) {
    LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);     // ...sleep for (sleepMin*multi) cycles

  Serial.println("------------waking up--------------");
  i = 0;                                                  // reset sleep cycle counter

void FSread()    // read soil moisture
  digitalWrite(3, HIGH);                          //turn on power to sensor
  delay(warmup);                                  //give sensor time to stabilize

  // Serial.println(" ");

  total = 0;                                                              //reset reading
  for (int thisReading = 0; thisReading < numReadings; thisReading++) {   //take several reads
    readings[thisReading] = analogRead(SensorPin);
    total += readings[thisReading];                                       //add them up

  digitalWrite(3, LOW);                         //turn off power to sensor

  average = total / numReadings;                // calc reading average
  // Serial.print ("\nCurrent reading: ");
  // Serial.println (average);

  if (average < lowValue) {                     // catch outliers
    average = lowValue;
  else if (average > highValue) {
    average = highValue;

  fs_sen_map = map (average, lowValue, highValue, 100, 1);

  // Serial.print(" Mapped fs average: ");
  // Serial.println(fs_sen_map);

  fs_bat_map = map (fs_batValue, 2856 , mapmax , 0 , 100);

int readVcc() {
  // Read 1.1V reference against AVcc
  // set the reference to Vcc and the measurement to the internal 1.1V reference
#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
  ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
#elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
  ADMUX = _BV(MUX5) | _BV(MUX0);
#elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
  ADMUX = _BV(MUX3) | _BV(MUX2);
  ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);

  delay(2);                                                     // Wait for Vref to settle
  ADCSRA |= _BV(ADSC);                                          // Start conversion
  while (bit_is_set(ADCSRA, ADSC));                             // measuring

  uint8_t low  = ADCL;                                          // must read ADCL first - it then locks ADCH
  uint8_t high = ADCH;                                          // unlocks both

  fs_batValue = (high << 8) | low;

  fs_batValue = 1125300L / fs_batValue ;                        // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000
  return fs_batValue;                                           // Vcc in mV

void send_data() {

  data snd_data;                                                // set up data package
  snd_data.fs_sen_map = fs_sen_map;                             // pass data to data package
  snd_data.fs_bat_map = fs_bat_map;
  snd_data.retries = retries;

  Serial.print("Data to send: FS-Value = ");                    // show what we are about to send
  Serial.print(", mapped Bat value = ");

  RF24NetworkHeader header(hub_node);                           // where to send
  network.write(header, &snd_data, sizeof(snd_data));           // send 1st sample
  Serial.println("1st sample sent");
  retries = radio.getARC();                                     // get # of retries
  ok = network.write(header, &snd_data, sizeof(snd_data));      // send 2nd sample w/ updated retries

  if (ok) {                                                     // check success, show retries on 1st sample
    Serial.print("OK - Retries: ");
  else {
    Serial.print("FAILED - Retries: ");

Here is the relevant part of the RX code (it does a bunch of other stuff I left out for simplicity):

void n24listen() {
  //Serial.println("Start listen-function");


  while (network.available() ) {                              // anything there?

    data payload;
    RF24NetworkHeader header (hub_node);                      // if so, grab it and print it out, &payload, sizeof(payload));

    if (header.from_node == fs_node) {                        // data coming from soil moisture sensor

      fs_bat_map = payload.fs_bat_map;
      fs_sen_map = payload.fs_sen_map;                        // comes as mapped to %
      retries = payload.retries;

      sprintf(Time_fs, "%02d:%02d:%02d", hour(), minute(), second());

      currentMillis = millis();
      if (currentMillis - startMillis >= interval) {          //show debug every 2 seconds

        Serial.print("Feucht-Sensor: ");
        Serial.print(", Bat: ");
        Serial.print(", Retries: ");
        Serial.println(" ");

        startMillis = millis();

    else if (header.from_node == dht_node) {                            // data coming from dht

      dht_bat_map = payload.d_bat_map;                                  // set up received data variables

      dht_temp = map(payload.d_temp, 1, 255, 100, 400);                 // map back
      dht_temp = dht_temp / 10;

      dht_hum = map(payload.d_hum, 1, 255, 10, 1000);
      dht_hum = dht_hum / 10;

      sprintf(Time_dht, "%02d:%02d:%02d", hour(), minute(), second());  // get update time

      currentMillis = millis();
      if (currentMillis - startMillis >= interval) {                    //show debug every 2 seconds

        Serial.print("Inside Temp: ");
        Serial.print("; Hum: ");
        Serial.print("; Bat: ");
        Serial.println(" ");

        startMillis = millis();

    else {
      Serial.println ("Unknown header");

To repeat: Everything works - except that getARC() always tells me that it gave up after 5 tries, but retries are set to 15.

Thankful for any enlighnment why that is the case.

You should read Section 7.4.2 Auto Retransmission (ART) of the nRF24L01+ datasheet. There is an interaction between the data speed, the length of the message and the time to wait for an acknowledgement. You have the minimum wait of 250µsecs and I suspect that is not long enough.


Thank you for your response Robin. I have tried several delay periods all the way up to 15 - no effect.

I have never needed to use the Network feature myself but it adds a layer of complexity (and sloth) on top of the standard nRF24 library.

Have you tried testing without using the Network feature?

In your Original Post you say

With one transmission every 3 hours

I would never rely on a single radio transmission being successful.


I need to sit down and figure out exactly what the network library contributes. It took me daysndaysndays to get a nrf24l01 network with a hub and two nodes going - I now understand a bit more about it so I might figure it out.

I had a version where upon failed transmission it would simply try again after 5 minutes. But I am trying to keep (lipo) power consumption as low as possible. My aim was to use getARC to optimize TX and RX positioning, PA level, retries and delays. So I stumbled over the 5 retry max. But even that is a good indicator.

Its probably best to work with what I got, so I‘m not going to worry about it any more. Just wanted to check if it was a known issue or if I made a simple mistake.


This Simple nRF24L01+ Tutorial may help.

The examples are as simple as I could make them and they have worked for other Forum members.


+1 for the Simple nRF24L01+ Tutorial. A tremendous help for me when starting with the rf24.

I came across your valuable guide many times Robin. But I had started with the nrf24network library approach and wanted to get that working. (A new approach tends to create its own challenges....)

Like I said: everything works. Just wanted to figure out the getARC question.

Like I said: everything works. Just wanted to figure out the getARC question.

I had got the impression that you were interested in the getARC() function because things were not working perfectly. It's a function I have never used myself.


There is not working, working, working well ....... and perfect. Its not perfect yet.
Happy holidays!