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?
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.
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
Serial.begin(115200);
while (!Serial) { }
Serial.println("\nFS Transmitter Started");
delay(10);
SPI.begin();
radio.begin();
radio.setChannel(90);
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.setAddressWidth(5);
radio.setDataRate(RF24_250KBPS);
radio.setCRCLength(RF24_CRC_8); // Cyclic redundancy check
radio.openWritingPipe(FS_pipe); // open pipe
radio.stopListening(); // set mode to transmitter
network.begin(fs_node);
}
void loop() {
network.update();
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(average);
*/
Serial.println("-----------going to sleep----------\n");
Serial.flush();
while (i <= (sleepMin * multi)) {
LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF); // ...sleep for (sleepMin*multi) cycles
i++;
}
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;
}
//convert
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);
#else
ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
#endif
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() {
radio.powerUp();
network.update();
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(snd_data.fs_sen_map);
Serial.print(", mapped Bat value = ");
Serial.println(snd_data.fs_bat_map);
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: ");
Serial.println(snd_data.retries);
}
else {
Serial.print("FAILED - Retries: ");
Serial.println(snd_data.retries);
}
radio.powerDown();
}
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.
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.
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.
Aggertroll:
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.