nRF24 / RF24

OSI Layer 2 driver for nRF24L01 on Arduino & Raspberry Pi/Linux Devices
https://nrf24.github.io/RF24
GNU General Public License v2.0
2.25k stars 1.02k forks source link

Problem with communicating to the module #993

Open Sinamajidi opened 3 months ago

Sinamajidi commented 3 months ago

What radio module do you use?

nRF24L01 + PA/LNA

What driver board(s) do you use?

ESP32

If using Linux, what OS are you using?

No response

If using Linux, what RF24 driver did you select?

None

Describe your problem

I modified the Getting Started Example and attempted to send and receive one package using two different nRF24L01 + PA/LNA modules, one as the transmitter and the other as the receiver. However, I encountered an issue where no data was being sent or received, and the program seemed to get stuck after calling radio.begin(), which returned false for both modules. I thoroughly checked the wire connections, pins, and the program itself, but I couldn't find any problems. I suspect that the issue might be with the source code. Here is my code and the corresponding output from the serial monitor:


#include <SPI.h>
#include "printf.h"
#include "RF24.h"

#define CSN1 13
#define CSN2 19
#define CE1 14
#define CE2 22
#define MOSI1 12
#define MOSI2 21
#define SCK1 27
#define SCK2 23
#define MISO1 26
#define MISO2 1

RF24 radio(CE1, CSN1,2000000);

RF24 radio2(CE2, CSN2,2000000);

uint8_t address[][5] = { "Send", "Rec" };

bool radioNumber_1 = 0; 
bool radioNumber_2 = 1; 

bool role_1 = true;  // true = TX role, false = RX role
bool role_2 = false;  // true = TX role, false = RX role

String tx_msg = "Tx sent: Message From Tx.";

bool Setup_Tx(int);
bool Setup_Rx(int);

void Send_Tx(void);
void Send_Rx(void);

void setup() {
pinMode(CSN1, OUTPUT);
pinMode(CSN2, OUTPUT);

  Serial.begin(9600);
  while (!Serial) {
    // some boards need to wait to ensure access to serial over USB
  }

  Serial.println(F("\n\n\nStarting the nrf modules...\n"));

  //Starting Tx:

  int size_of_Tx_msg = sizeof(tx_msg);
  bool res1 = Setup_Tx(size_of_Tx_msg);

  //Starting Rx:

  bool res2 = Setup_Rx(size_of_Tx_msg);
  if(!(res1&&res2)){
    Serial.print("\n\nProgram Exit.\nIDLE...");

    while(1){
      delay(500);

    }
  }

}  // setup

void loop() {

  Serial.print("\nSending TX:\n");
  Send_Tx();
  Serial.print("\nTx Sent.\nRecieving Rx:\n");
  Send_Rx();
  Serial.print("\nRx Recieved.\n");
  delay(1000);
}  // loop

//<:::::::::::::::FUNCTIONS:::::::::::::::>//

bool Setup_Tx(int msg_lng){

  if (!radio.begin()) {
    Serial.println(F("\nradio hardware is not responding!!\n--------------\nDetails:\n"));
  printf_begin();

 radio.printDetails();
 Serial.print("\n--------------\n");
    return false;
  }

  int radioNumber = 0;

  // Set the PA Level low to try preventing power supply related problems
  // because these examples are likely run with nodes in close proximity to
  // each other.
  radio.setPALevel(RF24_PA_LOW);  // RF24_PA_MAX is default.

  // save on transmission time by setting the radio to only transmit the
  // number of bytes we need to transmit a float
  radio.setPayloadSize(msg_lng);  // float datatype occupies 4 bytes

  // set the TX address of the RX node into the TX pipe
  radio.openWritingPipe(address[radioNumber]);  // always uses pipe 0

  // set the RX address of the TX node into a RX pipe
  radio.openReadingPipe(1, address[!radioNumber]);  // using pipe 1

  // additional setup specific to the node's role
  if (role_1) {
    radio.stopListening();  // put radio in TX mode
  } else {
    radio.startListening();  // put radio in RX mode
  }

return true;

}

bool Setup_Rx(int msg_lng){

  if (!radio2.begin()) {
        Serial.println(F("\nradio2 hardware is not responding!!\n--------------\nDetails:\n"));
  printf_begin();

 radio.printDetails();
 Serial.print("\n--------------\n");
return false;
  }

  int radioNumber = 1;

  // Set the PA Level low to try preventing power supply related problems
  // because these examples are likely run with nodes in close proximity to
  // each other.
  radio2.setPALevel(RF24_PA_LOW);  // RF24_PA_MAX is default.

  // save on transmission time by setting the radio to only transmit the
  // number of bytes we need to transmit a float
  radio2.setPayloadSize(msg_lng);  // float datatype occupies 4 bytes

  // set the TX address of the RX node into the TX pipe
  radio2.openWritingPipe(address[radioNumber]);  // always uses pipe 0

  // set the RX address of the TX node into a RX pipe
  radio2.openReadingPipe(1, address[!radioNumber]);  // using pipe 1

  // additional setup specific to the node's role
  if (role_2) {
    radio2.stopListening();  // put radio in TX mode
  } else {
    radio2.startListening();  // put radio in RX mode
  }

return true;

}

void Send_Tx(){
digitalWrite(CSN2,LOW);
  SPI.begin(SCK1, MISO1, MOSI1, CSN1);
 // This device is a TX node

    unsigned long start_timer = micros();                // start the timer
    bool report = radio.write(&tx_msg, sizeof(tx_msg));  // transmit & save the report
    unsigned long end_timer = micros();                  // end the timer

    if (report) {
      Serial.print(F("Transmission successful! "));  // payload was delivered
      Serial.print(F("Time to transmit = "));
      Serial.print(end_timer - start_timer);  // print the timer result
      Serial.print(F(" us. Sent: "));
      Serial.println(tx_msg);  // print payload sent

    } else {
      Serial.println(F("Tx:  Transmission failed or timed out"));  // payload was not delivered
    }

    // to make this example readable in the serial monitor
    delay(1000);  // slow transmissions down by 1 second
SPI.end();

}

void Send_Rx(){
  digitalWrite(CSN1,LOW);
  SPI.begin(SCK2, MISO2, MOSI2, CSN2);
    String recieved;
    uint8_t pipe;
    if (radio.available(&pipe)) {              // is there a payload? get the pipe number that recieved it
      uint8_t bytes = radio.getPayloadSize();  // get the size of the payload
      radio.read(&recieved, bytes);             // fetch payload from FIFO
      Serial.print(F("Received "));
      Serial.print(bytes);  // print the size of the payload
      Serial.print(F(" bytes on pipe "));
      Serial.print(pipe);  // print the pipe number
      Serial.print(F(": "));
      Serial.println(recieved);  // print the payload's value
    }

    SPI.end();
}

And here is the Serial Monitor Output:


radio hardware is not responding!!
--------------
Details:

SPI Speedz      = 2 Mhz
STATUS          = 0x00 RX_DR=0 TX_DS=0 MAX_RT=0 RX_P_NO=0 TX_FULL=0
RX_ADDR_P0-1    = 0x0000000000 0x0000000000
RX_ADDR_P2-5    = 0x00 0x00 0x00 0x00
TX_ADDR         = 0xffffffffff
RX_PW_P0-6      = 0x00 0x00 0xff 0x00 0x00 0x00
EN_AA           = 0x00
EN_RXADDR       = 0x00
RF_CH           = 0xff
RF_SETUP        = 0x00
CONFIG          = 0xff
DYNPD/FEATURE   = 0xff 0x00
Data Rate       = 1 MBPS
Model           = nRF24L01+
CRC Length      = Disabled
PA Power        = PA_MIN
ARC             = 0

--------------

radio2 hardware is not responding!!
--------------
Details:

SPI Speedz      = 2 Mhz
STATUS          = 0xff RX_DR=1 TX_DS=1 MAX_RT=1 RX_P_NO=7 TX_FULL=1
RX_ADDR_P0-1    = 0xffffffffff 0xffffffffff
RX_ADDR_P2-5    = 0xff 0xff 0xff 0xff
TX_ADDR         = 0xffffffffff
RX_PW_P0-6      = 0xff 0xff 0xff 0xff 0xff 0xff
EN_AA           = 0xff
EN_RXADDR       = 0xff
RF_CH           = 0xff
RF_SETUP        = 0xff
CONFIG          = 0xff
DYNPD/FEATURE   = 0xff 0xff
Data Rate       = 1 MBPS
Model           = nRF24L01+
CRC Length      = 16 bits
PA Power        = PA_MAX
ARC             = 15

--------------

Program Exit.
IDLE...
2bndy5 commented 3 months ago

Did you check that the power ($P = I * V$) is sufficient? Most problems with PA/LNA modules are due to unstable or inadequate power supply, nothing the source code can fix.

FYI, if RF24::begin() returns false then anything output by printDetails() is useless because the SPI bus isn't working (which could also be a power problem).

Sinamajidi commented 3 months ago

@2bndy5

Well, I just connected it to my laptop USB port, which can supply 0.5A@5V, but I will test it with an adaptor. Thank you for mentioning that.

But here a question pops up: How can I know if the module has a problem physically, I mean, for example, the nRF IC is not working? Can I say the IC is working according to Serial monitor details or not? Bcz I have no idea about those details.

2bndy5 commented 3 months ago

If its a power problem, then its a hardware problem. there's nothing the software can do to indicate this.

RF24::begin() returns false when it fails to setup the radio using the SPI bus. printDetails() uses the SPI bus to get information from the chip. There is a RF24::check_connection() function, but it basically does the same thing RF24::begin() does (with less repeated overhead): try to write then read the same value over SPI.

We have a section in the COMMON_ISSUES doc that talks about troubleshooting PA/LNA modules.

2bndy5 commented 3 months ago

BTW, most ESP32 boards famously consume a lot of power. This often leaves little power left on the 3.3V bus for peripheral sensors (like external radios).

Its very common to use an adapter board that takes a dedicated 5V supply and regulates that into a stable 3.3V supply for PA/LNA radios. That's the only way I got mine to work during tests.

[!important] FYI, the ground wire needs to be shared between the MCU and an external power supply. Otherwise the 0V reference is inconsistent between different parts of the circuit and causes very strange behavior.

Sinamajidi commented 3 months ago

Thank you. I will use one to see whether the problem is solved.

Sinamajidi commented 2 months ago

@2bndy5

I used NRFLite library from the link below, and the problem has been solved for me. It looks like there are some problems with the nRF24 library.

https://github.com/dparson55/NRFLite

2bndy5 commented 2 months ago

What happened with the adapter board idea?

The only difference I see between RF24 and NRFLite is that NRFLite enables all TX features (dynamic payloads, ACK payloads, and allows NO_ACK flag) and puts the radio into active RX mode when the radio is initiated. There's some other limiting factors... That lib's SPI speed is hard coded to 4 MHz; it doesn't look like that can be changed to the radio's max 10 MHz.

Sinamajidi commented 2 months ago

@2bndy5

Maybe the SPI speed is a noticeable difference, but I don't know what the main cause is that my nrf module works well with that library and not this. I uploaded a sample program of both libraries to esp32 to check, but just nRFLite is working for me now.

2bndy5 commented 2 months ago

ESP32 seems a bit finicky. I've recently had trouble init-ing the radio on a ESP32 board, but that was not using the Arduino framework (only the ESP-IDF support discussed in #925).

I delved into that lib's code, and I didn't see anything that looked different (behaviorally).

Sinamajidi commented 2 months ago

Maybe there is a problem with the init-ing, as you said with registers as an example or other parts, I don't know, but I suggest looking the different deeper, not just behaviorally.

About adapter idea that you just said Im still using laptop USB cable as main supply source and I'm not using any external regulator which is not appropriate setup, I know, it's still experimental, but with the same setup just that library has been worked well for me.

one interesting thing I noticed was that after I'm using a wrist ground band (I don't know its technical name), the packet loss ratio decreased a lot.

2bndy5 commented 2 months ago

after I'm using a wrist ground band (I don't know its technical name), the packet loss ratio decreased a lot.

That's because laptops' power supply are usually not earth-grounded (due to use of a battery as primary power source). Your wrist is probably providing the path to earth ground. Some laptops' charging circuits might extend earth ground when plugged into the wall, but that feature wouldn't work if charging from a battery pack.

Sinamajidi commented 2 months ago

Yeah, you're right. I connected the wristband to the laptop USB port's ground as global ground in the modules and esp32, so I think it's okay.

TMRh20 commented 2 months ago

About adapter idea that you just said Im still using laptop USB cable as main supply source and I'm not using any external regulator which is not appropriate setup, I know, it's still experimental, but with the same setup just that library has been worked well for me.

I would assume that the reason the other library works has to do with the configuration, not necessarily a problem with the RF24 library. This lib is designed for max performance by default, and I think you might have better luck with a better power supply.

The grounding problem leads me to believe that you have power supply issues also.

Have you seen our https://github.com/nRF24/RF24/blob/master/COMMON_ISSUES.md document? (Scroll down for the PA + LNA section)

I would suggest trying to apply the same settings/configuration in the RF24 library and see if that makes a difference.

RF24 radio(7, 8, 4000000); radio.enableDynamicPayloads();

and experiment with the PA Level or LNA enable: radio.setPALevel(RF24_PA_HIGH,0); - to set PA to HIGH and disable the LNA.

This should get you working with the RF24 library in theory, but it is possible there is something different between the libraries that is causing this behaviour. I am curious to know whether it is a library issue or a settings issue, as I have never had a problem getting even bad clones like the SI24R1 to work with this library.