NRF24L01+ not working - is the module itself defective?

Hello guys,

I have been trying to get the NRF24L01+ wireless communication between my two Arduino Pro Micro working as a part of my project. After spending several hours by learning how to get this thing done and experimenting with some libraries, checking wiring and so on, I made some progress, but it seems to me that one of my RF modules is not working properly. I got this simple sketch just to display the debugging information:

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

RF24 radio(3,2);

void setup()
{
 while (!Serial);
 Serial.begin(9600);
 printf_begin();
 radio.begin();
 radio.setDataRate(RF24_2MBPS);
 radio.setPALevel(RF24_PA_LOW);
}

void loop()
{
 radio.printDetails();
 delay(5000);
}

When I wire one RF module, let’s call it the “good guy”, I get the following debug info (using the radio.printDetails()):

STATUS		 = 0x0e RX_DR=0 TX_DS=0 MAX_RT=0 RX_P_NO=7 TX_FULL=0
RX_ADDR_P0-1	 = 0xe7e7e7e7e7 0xc2c2c2c2c2
RX_ADDR_P2-5	 = 0xc3 0xc4 0xc5 0xc6
TX_ADDR		 = 0xe7e7e7e7e7
RX_PW_P0-6	 = 0x00 0x00 0x00 0x00 0x00 0x00
EN_AA		 = 0x3f
EN_RXADDR	 = 0x03
RF_CH		 = 0x4c
RF_SETUP	 = 0x0b
CONFIG		 = 0x0e
DYNPD/FEATURE	 = 0x00 0x00
Data Rate	 = 2MBPS
Model		 = nRF24L01+
CRC Length	 = 16 bits
PA Power	 = PA_LOW

After trying to change some properties (transfer rate and PA power) changing these two lines in setup() part

radio.setDataRate(RF24_2MBPS);
radio.setPALevel(RF24_PA_LOW);

and re-uploading , it works OK

STATUS		 = 0x0e RX_DR=0 TX_DS=0 MAX_RT=0 RX_P_NO=7 TX_FULL=0
RX_ADDR_P0-1	 = 0xe7e7e7e7e7 0xc2c2c2c2c2
RX_ADDR_P2-5	 = 0xc3 0xc4 0xc5 0xc6
TX_ADDR		 = 0xe7e7e7e7e7
RX_PW_P0-6	 = 0x00 0x00 0x00 0x00 0x00 0x00
EN_AA		 = 0x3f
EN_RXADDR	 = 0x03
RF_CH		 = 0x4c
RF_SETUP	 = 0x05
CONFIG		 = 0x0e
DYNPD/FEATURE	 = 0x00 0x00
Data Rate	 = 1MBPS
Model		 = nRF24L01+
CRC Length	 = 16 bits
PA Power	 = PA_HIGH

But, when I wire the other RF module, the “bad guy” (using the exactly same setup, I just switch the modules on the same wires, Arduino, everyting), I get the following debug and it stays the same, no matter what I set up in the code:

STATUS		 = 0x0e RX_DR=0 TX_DS=0 MAX_RT=0 RX_P_NO=7 TX_FULL=0
RX_ADDR_P0-1	 = 0xe7e7e7e7e7 0xc2c2c2c2c2
RX_ADDR_P2-5	 = 0xc3 0xc4 0xc5 0xc6
TX_ADDR		 = 0xe7e7e7e7e7
RX_PW_P0-6	 = 0x00 0x00 0x00 0x00 0x00 0x00
EN_AA		 = 0x3f
EN_RXADDR	 = 0x03
RF_CH		 = 0x02
RF_SETUP	 = 0x0f
CONFIG		 = 0x08
DYNPD/FEATURE	 = 0x00 0x00
Data Rate	 = 2MBPS
Model		 = nRF24L01
CRC Length	 = 8 bits
PA Power	 = PA_MAX

Not even adding the 10 microfarad capacitor into the power line helped. I bought those two modules on e-bay from the same guy as a pair, so I would assume they are the same (at least they look so :slight_smile: ).

So the question now is - does the above mentioned results of debugging mean that the “bad guy” module is broken, or am I missing something here? Unfortunately, I only got two, so I can’t test any other :slight_smile: But it’s not a big problem to get a new one - I just want to know, that my assumption of a broken module is correct and I am not doing anyting else in a wrong way, so I don’t run into same trouble with new module…

Hi,
Can you please post a copy of your circuit, in CAD or a picture of a hand drawn circuit in jpg, png?
We need to see your hardware connections to make sure that the rf units are connected correctly.

Thanks… Tom… :slight_smile:

I got my nRF24s working with this Tutorial

I suggest you use the TMRh20 version of the RF24 library - it solves some problems from the ManiacBug version

The pair of programs in this link may be useful.

I would recommend working with the Tutorial until you get communication working. Wireless can be very difficult to debug so don't stray from a known working system.

If you think one of your modules is faulty I suggest you get another known good module rather than trying dozens of variations on the code.

...R

@TomGeorge: As for the circuit... please don't hate me and don't laugh too much :-D Pen, paper and cell phone is all I have here right now, so here it goes :-D

Warning: Sorry, I got the CE/CSN swapped in the picture. In actual circuit, CE goes to pin 3 and CSN to pin 2.

@Robin2: I started off with this Tutorial, but soon ran into problems with proceeding, so I started using the debug info and it led me to think that something went wrong with my module. At least the situation where one reacts "as expected" and the other one doesn't react to any changes at all leads me to think so.

I might try your library. I used another one, but it should be up-to-date and seems working (with the "good guy" module).

Anyway, thank you both for your effort so far ;-)

It is definitely not "my" library.

If you post the code you tried when following the Tutorial I linked to I will try it on my Arduinos.

I even have an nRF24 working with a Sparkfun Pro-micro.

What is the thing you have labeled "LE 33"

...R

The "your" library referred to "the one you posted", not necesarilly actually yours :-)

LE33 is just voltage regulator converting 5 V on Arduino's VCC to 3.3 V which is input to RF.

I am not at home atm, may post it later, but anyway, isn't it strange that on my circuit, one RF reacts OK to the settings change through sketch above and the other one, in the absolutely same circuit, does not? This leads me to think that the other RF is broken...

Is it, perhaps, the sound of one-hand clapping?

How can you test one on its own. You need at least two.

...R

PictusCZ: isn't it strange that on my circuit, one RF reacts OK to the settings change through sketch above and the other one, in the absolutely same circuit, does not? This leads me to think that the other RF is broken...

I think the fact that you can program the 'bad guy' to the defaults shows that it basically works. Bad modules (or bad wiring) normally show different patterns when read back after a default configuration. Often only 0x00 or 0xFF, once I've seen the address of the register as data.

@Robin2: In one of the tutorials, they suggested to test the wiring and basic functionality and reaction of a RF module by displaying debug info and changing some settings, to see if Arduino really communicates with that module properly. So I did this after failing some absolutely basic tests like sending "Hello world" from one to another.

@Whandall: No, I didn't program anything... All you can achieve is to display debug info. Nothing more. Never.

I tried to test the modules in transmission using GettingStarted (or how is it called) sketch from maniacBug RF library, but with no success... When I wired the "good guy" as a transmitter, it transmitted, but didn't receive the response from receiver. When I wired the "good guy" as a receiver, it was able to catch some other signals, but not the one from the transmitter (the "bad guy" that time). The "bad one" didn't seem to have done anything but display debug info yet...

I might give TMRh20 version of RF24 library a try and then I am probably gonna try a new one... If I find out the "bad guy" is actually OK, I might use it later. If not, I won't spend several more hours laboring over nonfunctional RF module :-)

radio.begin programs the chip with a couple of things which are displayed by printDetailails (Channel).

Here from the mother of all NRFdrivers (maniacbug version with fixed powerUp problem)

bool RF24::begin(void)
{

  uint8_t setup=0;

  #if defined (RF24_LINUX)

    SPI();
    
    #if defined (MRAA)
      GPIO();  
      gpio.begin(ce_pin,csn_pin);  
    #endif


    switch(csn_pin){     //Ensure valid hardware CS pin
      case 0: break;
      case 1: break;
      // Allow BCM2835 enums for RPi
      case 8: csn_pin = 0; break;
      case 7: csn_pin = 1; break;
      default: csn_pin = 0; break;
    }   

    _SPI.begin(csn_pin);

    pinMode(ce_pin,OUTPUT);
    ce(LOW);    

    delay(100);
  
  #elif defined(LITTLEWIRE)
    pinMode(csn_pin,OUTPUT);
    _SPI.begin();
    csn(HIGH);
  #else
    // Initialize pins
    if (ce_pin != csn_pin) pinMode(ce_pin,OUTPUT);  
  
    #if ! defined(LITTLEWIRE)
      if (ce_pin != csn_pin)
    #endif
        pinMode(csn_pin,OUTPUT);
    
    _SPI.begin();
    ce(LOW);
   csn(HIGH);
   #if defined (__ARDUINO_X86__)
        delay(100);
   #endif
  #endif //Linux

  // Must allow the radio time to settle else configuration bits will not necessarily stick.
  // This is actually only required following power up but some settling time also appears to
  // be required after resets too. For full coverage, we'll always assume the worst.
  // Enabling 16b CRC is by far the most obvious case if the wrong timing is used - or skipped.
  // Technically we require 4.5ms + 14us as a worst case. We'll just call it 5ms for good measure.
  // WARNING: Delay is based on P-variant whereby non-P *may* require different timing.
  delay( 5 ) ;

  // Reset CONFIG and enable 16-bit CRC.
  write_register( CONFIG, 0b00001100 ) ;

  // Set 1500uS (minimum for 32B payload in ESB@250KBPS) timeouts, to make testing a little easier
  // WARNING: If this is ever lowered, either 250KBS mode with AA is broken or maximum packet
  // sizes must never be used. See documentation for a more complete explanation.
  setRetries(5,15);

  // Reset value is MAX
  //setPALevel( RF24_PA_MAX ) ;

  // check for connected module and if this is a p nRF24l01 variant
  //
  if( setDataRate( RF24_250KBPS ) )
  {
    p_variant = true ;
  }
  setup = read_register(RF_SETUP);
  /*if( setup == 0b00001110 )     // register default for nRF24L01P
  {
    p_variant = true ;
  }*/
  
  // Then set the data rate to the slowest (and most reliable) speed supported by all
  // hardware.
  setDataRate( RF24_1MBPS ) ;

  // Initialize CRC and request 2-byte (16bit) CRC
  //setCRCLength( RF24_CRC_16 ) ;

  // Disable dynamic payloads, to match dynamic_payloads_enabled setting - Reset value is 0
  toggle_features();
  write_register(FEATURE,0 );
  write_register(DYNPD,0);

  // Reset current status
  // Notice reset and flush is the last thing we do
  write_register(NRF_STATUS,_BV(RX_DR) | _BV(TX_DS) | _BV(MAX_RT) );

  // Set up default configuration.  Callers can always change it later.
  // This channel should be universally safe and not bleed over into adjacent
  // spectrum.
  setChannel(76);

  // Flush buffers
  flush_rx();
  flush_tx();

  powerUp(); //Power up by default when begin() is called

  // Enable PTX, do not write CE high so radio will remain in standby I mode ( 130us max to transition to RX or TX instead of 1500us from powerUp )
  // PTX should use only 22uA of power
  write_register(CONFIG, ( read_register(CONFIG) ) & ~_BV(PRIM_RX) );

  // if setup is 0 or ff then there was no response from module
  return ( setup != 0 && setup != 0xff );
}

Ok, my bad, you are right, I did not realize the radio.begin(). Still, the bad guy is suspicious.. the default value should be 1 MBps (from code you posted), but it comes up with 2 whatever I do. I am pretty sure about this as I wanted to reduce it to match the defaults of the other one. But no luck doing that... I am probably gonna give try to TMRh20 version of library and if that doesn't help, I am sort of out of ideas what else (except RF module itself) can be wrong...

OK, so I tried TMRh20 version of library. Still the same, same old story. The "good guy" reacts to settings change through sketch seamlessly, the "bad guy" is just able to send the debug info.

According to this chunk of code found in RF24.cpp in RF24::begin

setDataRate( RF24_1MBPS ) ;

The radio.begin() should program the RF module to have the 1MBPS default transfer rate. Which, apparently, doesn't happen. So as it seems to me, not even radio.begin() has the power to persuade the "bad" RF module to change its' settings.

Help greatly appreciated, guys, but I am out of further ideas right now, so I am probably just gonna buy a new RF and try it :-)

PictusCZ: Help greatly appreciated, guys, but I am out of further ideas right now, so I am probably just gonna buy a new RF and try it :-)

The offer in Reply #4 remains open. But I would definitely buy a new nRF24 as the first next step.

...R

Thanks a lot for your offer. I browsed through the Tutorial you posted once again and as far as I remember, I might have stepped off to another web, as I wasn't really sure how to pin it correctly to my Pro Micro (as the Tutorial is shown using another board), so I googled some other tutorial tailored to Pro Micro, just to know the pinout. There I got the RF24 library, but the maniacBug version. At first, I got some older version, which didn't even write out the radio.printDetails(). So, after some googling, I fetched updated one. Which works the same way (in terms of the result) with my RFs as the TMRh20's did this morning.

As for the sketches I used:

  • GettingStarted example sketch (part of RF24 library)

After some attempts which didn't lead to success, I also tried this sketch:

http://starter-kit.nettigo.eu/2014/connecting-and-programming-nrf24l01-with-arduino-and-other-boards/

Guess you are gonna have success with both of them.. :-)

You need to post YOUR code here if I am to help. I am not going to make guesses about how you implement code from a website.

And please stick with the tutorial I am familiar with.

...R

The Tutorial you are familiar with references the GettingStarted (I found out that I eventually used the TMRh20 version, although first try was with maniacBug - sorry for initial misleading info, I worked on those RFs till late night hours and didn't remember it all) example. I used it unchanged, as it is in Arduino IDE (File-Examples...), except for

RF24 radio(3,2);

to set my pins correctly according to my actual circuit setup.

I also used the "Hello World" tutorial (mentioned above), also only change made

RF24 radio(3,2);

As my tests with both of these failed, I made a very simple "testing" sketch (see the first post) to set PA level and transfer rate different from default values and writing out the debug info. Cause in one of the other webs, I read that trying to change some settings and seeing the debug info that radio.printDetails() gives is a good clue to find out if everything is wired and working correctly.

Is this info OK with you?

PictusCZ: Is this info OK with you?

It's not what I have in mind.

All I want you to do is copy the complete program that YOU are uploading to YOUR Arduino and paste it here. Then I can copy it and upload it to my Arduino and try it. That is the only way I can be absolutely certain I have the same code as you have.

If you have a pair of transmit and receive programs please post both of them.

...R

OK, when I get home, I will do that... If you need me to actually copy&paste it here, I might do it, no problem.

Would you, in the meantime, test that short "testing" sketch from the first post? I guess your RFs should both end up producing the same debug output (2MBPS, PA_LOW), right? :-) Cause one of mine is not :-)

Anyway, thanks and I will copy&paste the code here when I get home...

My modules show the desired behaviour

STATUS       = 0x0e RX_DR=0 TX_DS=0 MAX_RT=0 RX_P_NO=7 TX_FULL=0
RX_ADDR_P0-1     = 0xe7e7e7e7e7 0xc2c2c2c2c2
RX_ADDR_P2-5     = 0xc3 0xc4 0xc5 0xc6
TX_ADDR      = 0xe7e7e7e7e7
RX_PW_P0-6   = 0x00 0x00 0x00 0x00 0x00 0x00
EN_AA        = 0x3f
EN_RXADDR    = 0x03
RF_CH        = 0x4c
RF_SETUP     = 0x07
CONFIG       = 0x0e
DYNPD/FEATURE    = 0x00 0x00
Data Rate    = 1MBPS
Model        = nRF24L01+
CRC Length   = 16 bits
PA Power     = PA_MAX

change to 2MBPS and PA_LOW

STATUS       = 0x0e RX_DR=0 TX_DS=0 MAX_RT=0 RX_P_NO=7 TX_FULL=0
RX_ADDR_P0-1     = 0xe7e7e7e7e7 0xc2c2c2c2c2
RX_ADDR_P2-5     = 0xc3 0xc4 0xc5 0xc6
TX_ADDR      = 0xe7e7e7e7e7
RX_PW_P0-6   = 0x00 0x00 0x00 0x00 0x00 0x00
EN_AA        = 0x3f
EN_RXADDR    = 0x03
RF_CH        = 0x4c
RF_SETUP     = 0x0b
CONFIG       = 0x0e
DYNPD/FEATURE    = 0x00 0x00
Data Rate    = 2MBPS
Model        = nRF24L01+
CRC Length   = 16 bits
PA Power     = PA_LOW

The PA setting seems to be untouched by begin() and there is no reset for the NRF, so it will only return to default after a power cycle. Second run after power cycle shows

STATUS       = 0x0e RX_DR=0 TX_DS=0 MAX_RT=0 RX_P_NO=7 TX_FULL=0
RX_ADDR_P0-1     = 0xe7e7e7e7e7 0xc2c2c2c2c2
RX_ADDR_P2-5     = 0xc3 0xc4 0xc5 0xc6
TX_ADDR      = 0xe7e7e7e7e7
RX_PW_P0-6   = 0x00 0x00 0x00 0x00 0x00 0x00
EN_AA        = 0x3f
EN_RXADDR    = 0x03
RF_CH        = 0x4c
RF_SETUP     = 0x03
CONFIG       = 0x0e
DYNPD/FEATURE    = 0x00 0x00
Data Rate    = 1MBPS
Model        = nRF24L01+
CRC Length   = 16 bits
PA Power     = PA_LOW

change to 2MBPS and PA_LOW

STATUS       = 0x0e RX_DR=0 TX_DS=0 MAX_RT=0 RX_P_NO=7 TX_FULL=0
RX_ADDR_P0-1     = 0xe7e7e7e7e7 0xc2c2c2c2c2
RX_ADDR_P2-5     = 0xc3 0xc4 0xc5 0xc6
TX_ADDR      = 0xe7e7e7e7e7
RX_PW_P0-6   = 0x00 0x00 0x00 0x00 0x00 0x00
EN_AA        = 0x3f
EN_RXADDR    = 0x03
RF_CH        = 0x4c
RF_SETUP     = 0x0b
CONFIG       = 0x0e
DYNPD/FEATURE    = 0x00 0x00
Data Rate    = 2MBPS
Model        = nRF24L01+
CRC Length   = 16 bits
PA Power     = PA_LOW

@Robin2: OK, here we go, first the GettingStarted. Grabbed from TMRh20’s library, examples… Had some success with the “Good guy” - was sending something into the air when used as a transmitter (role 1) and tried to listen to something when set as receiver (role 0).

No success in any of these with “bad guy” - the suspectedly broken RF module. When used as a transmitter, it gets stuck at “Now sending” line. When used as a receiver, the serial monitor remains empty.

/*
* Getting Started example sketch for nRF24L01+ radios
* This is a very basic example of how to send data from one node to another
* Updated: Dec 2014 by TMRh20
*/

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

/****************** User Config ***************************/
/***      Set this radio as radio number 0 or 1         ***/
bool radioNumber = 0;

/* Hardware configuration: Set up nRF24L01 radio on SPI bus plus pins 7 & 8 */
RF24 radio(3,2);
/**********************************************************/

byte addresses[][6] = {"1Node","2Node"};

// Used to control whether this node is sending or receiving
bool role = 1;

void setup() {
  Serial.begin(115200);
  while (!Serial);  
  Serial.println(F("RF24/examples/GettingStarted"));
  Serial.println(F("*** PRESS 'T' to begin transmitting to the other node"));
  
  radio.begin();

  // Set the PA Level low to prevent power supply related issues since this is a
 // getting_started sketch, and the likelihood of close proximity of the devices. RF24_PA_MAX is default.
  radio.setPALevel(RF24_PA_LOW);
  
  // Open a writing and reading pipe on each radio, with opposite addresses
  if(radioNumber){
    radio.openWritingPipe(addresses[1]);
    radio.openReadingPipe(1,addresses[0]);
  }else{
    radio.openWritingPipe(addresses[0]);
    radio.openReadingPipe(1,addresses[1]);
  }
  
  // Start the radio listening for data
  radio.startListening();
}

void loop() {
  
  
/****************** Ping Out Role ***************************/  
if (role == 1)  {
    
    radio.stopListening();                                    // First, stop listening so we can talk.
    
    Serial.println(F("Now sending"));

    unsigned long start_time = micros();                             // Take the time, and send it.  This will block until complete
     if (!radio.write( &start_time, sizeof(unsigned long) )){
       Serial.println(F("failed"));
     }
        
    radio.startListening();                                    // Now, continue listening
    
    unsigned long started_waiting_at = micros();               // Set up a timeout period, get the current microseconds
    boolean timeout = false;                                   // Set up a variable to indicate if a response was received or not
    
    while ( ! radio.available() ){                             // While nothing is received
      if (micros() - started_waiting_at > 200000 ){            // If waited longer than 200ms, indicate timeout and exit while loop
          timeout = true;
          break;
      }      
    }
        
    if ( timeout ){                                             // Describe the results
        Serial.println(F("Failed, response timed out."));
    }else{
        unsigned long got_time;                                 // Grab the response, compare, and send to debugging spew
        radio.read( &got_time, sizeof(unsigned long) );
        unsigned long end_time = micros();
        
        // Spew it
        Serial.print(F("Sent "));
        Serial.print(start_time);
        Serial.print(F(", Got response "));
        Serial.print(got_time);
        Serial.print(F(", Round-trip delay "));
        Serial.print(end_time-start_time);
        Serial.println(F(" microseconds"));
    }

    // Try again 1s later
    delay(1000);
  }



/****************** Pong Back Role ***************************/

  if ( role == 0 )
  {
    unsigned long got_time;
    
    if( radio.available()){
                                                                    // Variable for the received timestamp
      while (radio.available()) {                                   // While there is data ready
        radio.read( &got_time, sizeof(unsigned long) );             // Get the payload
      }
     
      radio.stopListening();                                        // First, stop listening so we can talk   
      radio.write( &got_time, sizeof(unsigned long) );              // Send the final one back.      
      radio.startListening();                                       // Now, resume listening so we catch the next packets.     
      Serial.print(F("Sent response "));
      Serial.println(got_time);  
   }
 }




/****************** Change Roles via Serial Commands ***************************/

  if ( Serial.available() )
  {
    char c = toupper(Serial.read());
    if ( c == 'T' && role == 0 ){      
      Serial.println(F("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK"));
      role = 1;                  // Become the primary transmitter (ping out)
    
   }else
    if ( c == 'R' && role == 1 ){
      Serial.println(F("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK"));      
       role = 0;                // Become the primary receiver (pong back)
       radio.startListening();
       
    }
  }


} // Loop

… another code I used was this, the “Hello world” tutorial:

Transmitter part:

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>

RF24 radio(3, 2);

const byte rxAddr[6] = "00001";

void setup()
{
  radio.begin();
  radio.setRetries(15, 15);
  radio.openWritingPipe(rxAddr);
  
  radio.stopListening();
}

void loop()
{
  const char text[] = "Hello World";
  radio.write(&text, sizeof(text));
  
  delay(1000);
}:

Receiver part:

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>

RF24 radio(7, 8);

const byte rxAddr[6] = "00001";

void setup()
{
  while (!Serial);
  Serial.begin(9600);
  
  radio.begin();
  radio.openReadingPipe(0, rxAddr);
  
  radio.startListening();
}

void loop()
{
  if (radio.available())
  {
    char text[32] = {0};
    radio.read(&text, sizeof(text));
    
    Serial.println(text);
  }
}

I wish you better luck with your RFs than I had with mine :slight_smile: Anyway, new one has been ordered and I am picking it in two days :slight_smile: