RF24
RF24 copied to clipboard
Problems caused by differences between versions v1.4.5 and v1.3.2
Hi,
I recently updated the rf24 library from v1.3.2 to v1.4.5, but after the update, I found that the original user code did not work properly. With the same user code, it is normal to use the v1.3.2 library, but not normal to use v1.4.5.
The specific behaviors are as follows: the communication between two rf24 is very unstable. When the distance between the two devices is about 20cm, the communication can be stable after power on. However, after a period of time, sometimes several tens of seconds, sometimes several minutes, the connection will be disconnected. When the distance between the two devices is more than two meters, the communication will also be disconnected, and the communication cannot be resumed even if they approach again.
These situations do not exist when using the v1.3.2 library.
This is obviously abnormal, so I checked the rf24.cpp code in v1.4.5 and v1.3.2. I found that the code write_register(NRF_STATUS,_BV(MAX_RT) ); in line 927 in v1.3.2 was deleted. I restored it to the corresponding position in v1.4.5. Then I found that I succeeded and v1.4.5 could work normally. I want to know why? Why is this code deleted?
Thanks for any answers!
Transmitter code:
#include <SPI.h>
#include "RF24.h"
RF24 radio(9, 10); // define the object to control NRF24L01
const byte addresses[6] = "Free1";// define communication address which should correspond to remote control
// wireless communication
int dataWrite[8]; // define array used to save the write data
// pin
const int pot1Pin = A0, // define POT1 Potentiometer
pot2Pin = A1, // define POT2 Potentiometer
joystickXPin = A2, // define pin for direction X of joystick
joystickYPin = A3, // define pin for direction Y of joystick
joystickZPin = 7, // define pin for direction Z of joystick
s1Pin = 4, // define pin for S1
s2Pin = 3, // define pin for S2
s3Pin = 2, // define pin for S3
led1Pin = 6, // define pin for LED1 which is close to POT1 and used to indicate the state of POT1
led2Pin = 5, // define pin for LED2 which is close to POT2 and used to indicate the state of POT2
led3Pin = 8; // define pin for LED3 which is close to NRF24L01 and used to indicate the state of NRF24L01
void setup() {
// NRF24L01
Serial.begin(9600);
radio.begin(); // initialize RF24
radio.setChannel(1);
radio.setAutoAck(true);
radio.setPALevel(RF24_PA_MAX); // set power amplifier (PA) level
radio.setDataRate(RF24_1MBPS); // set data rate through the air
radio.setRetries(3, 15); // set the number and delay of retries
radio.openWritingPipe(addresses); // open a pipe for writing
radio.openReadingPipe(1, addresses);// open a pipe for reading
radio.stopListening(); // stop listening for incoming messages
// pin
pinMode(joystickZPin, INPUT); // set led1Pin to input mode
pinMode(s1Pin, INPUT); // set s1Pin to input mode
pinMode(s2Pin, INPUT); // set s2Pin to input mode
pinMode(s3Pin, INPUT); // set s3Pin to input mode
pinMode(led1Pin, OUTPUT); // set led1Pin to output mode
pinMode(led2Pin, OUTPUT); // set led2Pin to output mode
pinMode(led3Pin, OUTPUT); // set led3Pin to output mode
}
int cnt = 0;
void loop()
{
// put the values of rocker, switch and potentiometer into the array
dataWrite[0] = analogRead(pot1Pin); // save data of Potentiometer 1
dataWrite[1] = analogRead(pot2Pin); // save data of Potentiometer 2
dataWrite[2] = analogRead(joystickXPin); // save data of direction X of joystick
dataWrite[3] = analogRead(joystickYPin); // save data of direction Y of joystick
dataWrite[4] = digitalRead(joystickZPin); // save data of direction Z of joystick
dataWrite[5] = digitalRead(s1Pin); // save data of switch 1
dataWrite[6] = digitalRead(s2Pin); // save data of switch 2
dataWrite[7] = digitalRead(s3Pin); // save data of switch 3
// write radio data
int res = radio.writeFast(&dataWrite, sizeof(dataWrite));
if (res)
{
Serial.print("1");
digitalWrite(led3Pin, HIGH);
}
else {
Serial.print("0");
digitalWrite(led3Pin, LOW);
}
delay(20);
cnt++;
if (cnt >= 50) {
cnt = 0;
Serial.println();
}
// make LED emit different brightness of light according to analog of potentiometer
analogWrite(led1Pin, map(dataWrite[0], 0, 1023, 0, 255));
analogWrite(led2Pin, map(dataWrite[1], 0, 1023, 0, 255));
}
Receiver code:
#include <SPI.h>
#include "RF24.h"
#define PIN_SPI_CE 9
#define PIN_SPI_CSN 10
RF24 radio(PIN_SPI_CE, PIN_SPI_CSN); // define an object to control NRF24L01
const byte addresses[6] = "Free1"; //set commucation address, same to remote controller
int nrfDataRead[8]; //define an array to save data from remote controller
void setup() {
Serial.begin(9600);
// NRF24L01
if (radio.begin()) { // initialize RF24
radio.setChannel(1);
radio.setAutoAck(true);
radio.setPALevel(RF24_PA_MAX); // set power amplifier (PA) level
radio.setDataRate(RF24_1MBPS); // set data rate through the air
radio.setRetries(0, 15); // set the number and delay of retries
radio.openWritingPipe(addresses); // open a pipe for writing
radio.openReadingPipe(1, addresses);// open a pipe for reading
radio.startListening(); // start monitoringtart listening on the pipes opened
Serial.println("Start listening remote data ... ");
}
else {
Serial.println("Not found the nrf chip!");
}
}
void loop() {
delayMicroseconds(1000);
if (radio.available()) { // if receive the data
while (radio.available()) { // read all the data
radio.read(nrfDataRead, sizeof(nrfDataRead)); // read data
}
Serial.print("P1/P2/X/Y/Z/S1/S2/S3 : ");
for (int i = 0; i < sizeof(nrfDataRead) / 2; i++) {
Serial.print(nrfDataRead[i]);
Serial.print('\t');
}
Serial.print('\n');
}
}
line 927 in v1.3.2 was deleted
It happened between https://github.com/nRF24/RF24/compare/v1.3.6...v1.3.7 More specifically, https://github.com/nRF24/RF24/commit/3af80f8fa4ddc741ef9d2f1b9793da0ab5047b1a
I'm kinda relieved to say this was before my time in this org.
Concerning your usage:
int res = radio.writeFast(&dataWrite, sizeof(dataWrite));
if (res)
{
Serial.print("1");
digitalWrite(led3Pin, HIGH);
}
else {
Serial.print("0");
digitalWrite(led3Pin, LOW);
}
There's seems to be some discrepancy in the docs where the return value described is slightly different between the the documented overloads.
In actuality (from reading the src code), the return value doesn't actually describe if the payload was sent and acknowledged. Rather the return value only describes if the payload was written to a level in the TX FIFO. Your choices are:
- use a normal
write()
. - call
txStandBy()
after callingwriteFast()
. However, this could block the TX node untiltxStandBy()
return the status of transmitting all payloads in the TX FIFO. - flush the TX FIFO when
writeFast()
returns false, but that may be considered data loss (even if the data is outdated). - use
reUseTx()
whenwriteFast()
returns false. This might also lead to data loss since the SPI command allows a new payload to overwrite an existing payload in the TX FIFO.
In fact, this comment kinda seems outdated without the MAX_RT flag getting cleared. https://github.com/nRF24/RF24/blob/89358b2df7de37d64f2bba180d61b6d200c54070/RF24.cpp#L1352
I'd be more concerned with why your receiver loses connection because that is why you transmitter's FIFO is filling up.
Remember that if the receiver's RX FIFO is full, then no incoming payloads are allowed in.
radio.setChannel(1);
Have tried switching to a higher channel? Lower channels are typically quite noisy (with interference).
I've taken a quick look at this, and honestly I don't know why it stops working, but two workarounds are:
- Disable Auto-Ack - It should work fine without auto-ack enabled
- Call
radio.txStandBy();
after callingradio.write();
I'll take a closer look at this when I have a chance...
"When transmitting data in rapid succession, it is still recommended by the manufacturer to drop the radio out of TX or STANDBY-II mode if there is time enough between sends for the FIFOs to empty. This is not required if auto-ack is enabled."
Might have to change this comment in the docs...
We could manually turn off the CE pin when MAX_RT is asserted during writeFast()
.
I'm not sure what effect that would have?
drop the radio out of TX or STANDBY-II mode
Hmmm, interesting.
Technically, the radio should auto switch to Standby-I mode if the FIFO is full, but pulling down the CE pin should exit active TX mode entirely.
I don't really think I like that idea, it could cause data loss, where calling txStandby would ensure that data is sent.
All in all this looks like kind of a timing issue. It also seems to work if I set the Serial baud to 115200 on the receiver. I think the transmitter is simply sending data faster than the receiver can process it, then hitting MAX_RT. The flag never clears because txStandBy is never called.
What if the RX node stops printing to Serial? That should speed things up significantly on that end.
This also seems done for console readability:
delayMicroseconds(1000);
I think the issue will still happen when/if the receiver goes out of range. Either auto-ack should be disabled or call txStandBy() at some point in the code would be the fix/workaround.
I need to amend the docs about the writeFast()
return value. The one for writeFast(buf, len)
(no multicast) is definitely wrong.
Yeah, we might want to add a comment about hitting MAX_RT
if AA
is enabled, and the need to call txStandBy();
@SuhaylZhao
This should do the trick:
int res = radio.writeFast(&dataWrite, sizeof(dataWrite));
if (res)
{
Serial.print("1");
digitalWrite(led3Pin, HIGH);
}
else {
radio.txStandBy(); //<<------ ADD THIS
Serial.print("0");
digitalWrite(led3Pin, LOW);
}
Hi @2bndy5 @TMRh20 ,
Thank you!
I tried your suggestion. Here are the test results:
- use a normal write().
It doesn't work at all, but when I touch the pin of the rf24 module with my finger, it can work unstably. It looks like the rf24 module is broken (in fact it is good).
- call txStandBy() after calling writeFast()
writeFast() always returns true, even in the case of communication failure.
- flush the TX FIFO when writeFast() returns false.
It does not always return true, but it also returns true when communication fails.
- use reUseTx() when writeFast() returns false
It can work well.
- radio.txStandBy(); //<<------ ADD THIS
It can work well.
For the above 4 and 5, I guess the call of write_register(NRF_STATUS, _BV(MAX_RT));
function plays a key role.
I know that the radio.writeFast
function return true does not mean that the communication is really successful. However, it returns false, which means that there must be something wrong with the communication. Therefore, I can use an indicator to judge whether the current communication status is normal. In fact, satisfactory results can be achieved by using this method.
Thanks again for your help!
but when I touch the pin of the rf24 module with my finger, it can work unstably.
You could try scraping away any dirt from the antenna. There tends to be a build-up of dust (dirt particulate from the air) on radios that have been running for a while. I recently had to do this to all my test rigged radios (which use a builtin antennas), and it restored reception to what I had expected.
Otherwise, you might need to replace the added capacitor in your power circuit. These don't remain consistent indefinitely (depending on the chemical makeup).
Hi,
- use a normal write().
Rf24 module is a brand-new module I purchased. And I tested several, and they all have the same performance.
Are they PA/LNA type modules (which use an external antenna)?
Hi,
No, all the above tests are on-board antennas. like this:
At the same time, I tested the PA/LNA type module and found that everything was normal. The write
function can be used, and there is no need to call txStandBy
or reUseTX
in case of false.
writeFast() always returns true, even in the case of communication failure.
This sounds link you turned off AutoAck. writeFast()
can only report a failure if AutoAck is enabled.
Hi,
radio.setAutoAck(true);
Like the code shown on the first floor, the functions in setup have not been changed.
- call txStandBy() after calling writeFast()
- flush the TX FIFO when writeFast() returns false.
This does make the module work, but the problem is that writeFast()
cannot return the false I expected.
You may have some sort of power supply issues or something going on if the normal write() isn't working. Do you have a 10-100uF capacitor connected between the VCC and GND pins of the radio? If not you should try that.
This does make the module work, but the problem is that writeFast() cannot return the false I expected.
radio.writeFast(&dataWrite, sizeof(dataWrite));
int res = radio.txStandBy(); //<<------ ADD THIS
if (res)
{
Serial.print("1");
digitalWrite(led3Pin, HIGH);
}
else {
Serial.print("0");
digitalWrite(led3Pin, LOW);
}
I think the above code would be what you are looking for. It should return false every time a write fails.
Touching the radio and getting better results usually indicates a power instability.
Hi,
Do you have a 10-100uF capacitor connected between the VCC and GND pins of the radio? If not you should try that.
It has a 10 UF tantalum capacitor and a 0.1 UF ceramic capacitor.
Using the write()
function, and I tried 47uF and 220uF capacitors respectively, but they didn't work. Then I used an oscilloscope to observe the voltage waveform between VCC and GND of the module (using a capacitor of 47uF), and found that the power supply was very stable, with peak to peak jumping between 80-100mv. Whether I touch with my finger to enable him to communicate successfully or fail, the voltage will not change.
In addition, I have also made new discoveries. When I set setPALevel
to RF24_PA_MAX
and RF24_PA_HIGH
, the write()
function cannot work. However, when I set setPALevel
to RF24_PA_LOW
and RF24_PA_MIN
, the write()
function can work normally. Correspondingly, the transmission distance decreases to a certain extent.
When using write()
function, and module does not work, sometimes the touch pin will work, and sometimes the touch antenna will work.
radio.writeFast(&dataWrite, sizeof(dataWrite));
int res = radio.txStandBy(); //<<------ ADD THIS
It doesn't work, and its performance is the same as using only the write()
function.
At present, my practice is to use the writefast()
function, and call txStandBy()
or reUseTX()
when it returns false, which can make the module communicate well. The only problem is that I can't judge whether the current communication is good through the LED indicator. Because if it returns true, it does not mean that the communication is successful. If it returns false, it means that the communication must have failed.
In addition, I have also made new discoveries. When I set
setPALevel
toRF24_PA_MAX
andRF24_PA_HIGH
, thewrite()
function cannot work. However, when I setsetPALevel
toRF24_PA_LOW
andRF24_PA_MIN
, thewrite()
function can work normally. Correspondingly, the transmission distance decreases to a certain extent.
This a current-saving hack we use in the examples because some boards voltage regulators don't provide enough current to transmit. Use your oscilloscope to check the current, and see if it flat lines during transmission. It sounds like you need a stronger power source - stronger meaning higher current.
Hi,
I tested the PA/LNA type modules yesterday. They worked very well, and the working conditions were the same. Only the modules were replaced in the same slot. Can this show that the power supply is good?
That looks like an ebyte module. There are numerous kinds of the nRF24L01 radio from ebyte. I can't say anything else about that without seeing the store link you bought it from.
Side note
I recently had another user tell me that ebyte claimed to not support changing the PA level. But, that same user that directly asked ebyte about the PA level had a contradicting experience. So, I'm not entirely sure the specifications from ebyte are accurate.
There is a possibility that ebyte modules use the lna_enabled
parameter to setPALevel()
differently than the original nRF24L01. Some Chinese clones are known to do that.
Hi,
I found the above picture on the Internet. My module is like this. There are no characters on the shield.