Playing with NRF24L01, not working, need help debugging

Hi all, I need some help/pointers please:

I have 2 cheap NF24L01 modules I bought from eBay. I am trying them out by connecting them up as follows:

  • One connected to a Pro Micro, also attached to a 16x2 character LCD. This will be the receiver, and will display characters received over RF on the screen.
  • The other connected to a Nano 3. This will be the transmitter and will transmit, over RF, the characters it receives from the Serial Monitor. (It also echoes the characters back to the Serial Monitor for debugging purposes)

Nothing is happening when I try to send characters. I am at a bit of a loss what to try next for testing/debugging.

This is what I have tried so far: Ignoring both RF modules, I amended the receiver (the Pro Micro) sketch to pick up characters sent to its RXI pin and display these on the LCD (using Serial1.available() and Serial1.read() commands). Then, with a length of wire, I connected the TX pin on the transmitter (the Nano) to the RXI pin on the receiver (the Pro Micro). When I send characters from the Serial Monitor, they are displayed on the LCD. So at least that works.

Here are the 2 sketches. I have used a library called "Mirf", which I found on the Playground. I will create a couple of quick schematics and post them later, if you think that would help.

Transmitter sketch:

#include <SPI.h>
#include <Mirf.h>
#include <nRF24L01.h>
#include <MirfHardwareSpiDriver.h>

void setup() {
  Serial.begin(9600);
  
  Mirf.cePin = 10;
  Mirf.csnPin = A6;
  Mirf.spi = &MirfHardwareSpi;
  Mirf.init();
  Mirf.setRADDR((byte *)"clie2");
  Mirf.payload = sizeof(char);
  Mirf.config();
  
}

void loop() {
  while (Serial.available()) {
    char c = Serial.read();
    Mirf.setTADDR((byte *)"clie1");
    Mirf.send((byte *)&c);
    while(Mirf.isSending()){
    }
    Serial.write(c);
  }
}

Receiver Sketch:

#include <SPI.h>
#include <nRF24L01.h>
#include <Mirf.h>
#include <MirfSpiDriver.h>
#include <MirfHardwareSpiDriver.h>
#include <LiquidCrystal.h>

LiquidCrystal lcd(A3, A2, A1, A0, 10, 9);

void setup() {

  Mirf.cePin = 8;
  Mirf.csnPin = 7;
  Mirf.spi = &MirfHardwareSpi;
  Mirf.init();
  
  Mirf.setRADDR((byte *)"clie1");
  Mirf.payload = sizeof(char);
  Mirf.config();
  
  lcd.begin(16, 2);
  lcd.print("Ready...");
  
}

void loop() {
  while (Mirf.dataReady()) {
    char c;
    Mirf.getData((byte *) &c);
    if (c == 13) lcd.clear(); else lcd.write(c);
  }
}

Also attached are pictures of the transmitter and receiver circuits. Note that since the Pro Micro has no 3.3V output, I have used two diodes to drop the 5V down to about 3.1V (according to my DMM) to supply the RF module.

Any help would be appreciated!

Paul

PaulRB:
Nothing is happening when I try to send characters. I am at a bit of a loss what to try next for testing/debugging.

From the photo, it doesn't look like you've connected anything the the CE pin on the nRF24L01 module. If that's the case, nothing is going to be working.

Posting a schematic to see exactly how you've wired things would definitely help, keeping the guesswork out.

As for what to try next for testing and debugging, I'd recommend starting with a minimalist sketch to verify the hardware side of things. Once that's working, add functionality progressively. Much easier to debug starting with something that works.

Hi pico, thanks for responding. I see from your signature you have considerable experience with this type of RF chip, which is just what I need.

pico:
From the photo, it doesn't look like you've connected anything the the CE pin on the nRF24L01 module.

I think that's just the angle the photo was taken from. CE is connected to pin 10 on the Nano/transmitter and pin 8 on the Pro Micro/receiver. I will try to get those schematics posted this evening, even if they are only hand-drawn.

pico:
As for what to try next for testing and debugging, I'd recommend starting with a minimalist sketch to verify the hardware side of things. Once that's working, add functionality progressively. Much easier to debug starting with something that works.

Yes, absolutely. That's what I have done, I hope. The sketches are short and the circuits simple. As I said in my OP, I have tried a wired connection between the two Arduinos and proved to my satisfaction that everything else (other than the RF modules and their associated code) is working fine.

Paul

I would recommend that you make this a two stage process; first make sure that you are communicating properly with the module, then try to talk over the RF link to another module.
I suggest using the rf24 library as it has a nice function, printDetails(), that reports the register settings of the module. This will tell you if you are setting the module up correctly. The code below just sets up a few things and then prints out the status of the registers. (I haven't run this code but hopefully there are no syntax errors)

/**
 * First test
 *
 */

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

//
// Hardware configuration
//

// Configure nRF24L01 radio module on SPI bus plus pins 8 for CE & 9 for CS
// arguments are (ce, cs)

RF24 radio(8,9);

//
// Set transmit and receive addresses
//

const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL };

void setup(void)
{
 
  Serial.begin(9600);
  printf_begin();
  printf("\n\rTest connection to modules\n\r");

  //
  // Setup and configure rf radio
  //

  radio.begin();
  
  // Set the TX and RX addreses in the module
  
  radio.openWritingPipe(pipes[0]);
  radio.openReadingPipe(1,pipes[1]);
  

  // radio.setDataRate( RF24_2MBPS ) ;
  // radio.setPALevel( RF24_PA_MAX ) ;
  radio.enableDynamicPayloads() ;
  radio.setAutoAck( true ) ;
  radio.powerUp() ;
  radio.startListening();

  //
  // Print out the configuration of the rf unit for debugging
  //

  radio.printDetails();
}

void loop(void)
{
}

If this produces the right results then you can move onto talking to another unit.

Looking at your code I think you will be safer to use a hexadecimal string for the addresses initially.

crofter:
I suggest using the rf24 library

Thanks crofter, but I'm having problems with that. Can you advise further please.

I managed to find a copy of printf.h here but not sure if it is a good copy.

Saved it as printf.h into my sketchbook/library folder and restarted the IDE. But I can't compile:

RF_test_2.cpp:8:20: fatal error: printf.h: No such file or directory
compilation terminated.

Also, I downloaded the RF24 library as you suggested from here. Is this the one you meant? I had to change #include <RF24.h> to #include <NRF24.h> in your sketch.

Thanks,

Paul

The version of RF24 I am using is jscrane (Stephen Crane) · GitHub but there are many clones of the original http://maniacbug.github.com/RF24 around. Print.h is included in all of the RF24 example directories so create a new directory for your test program and copy print.h from one of the examples into the directory.
If you use the library above then the include will be RF24.h. Make sure you only have one version of RF24 in the libraries directory of the IDE or you may get unpredictable results.

OK thanks again crofter. I deleted all other RF24 folders from sketchbook/libraries, downloaded that same copy you use, found a copy of printf.h from one of the example folders, copied this into the folder for the sketch you gave above.

It would not compile until I edited printf.h and commented out the line: #include "WProgram.h". Hope that is OK.

I also changed the line that specifies which pins I am using: RF24 radio(10,A6); I hope those pins are OK too.

Here is the output:

Test connection to modules

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		 = 0x0000000000
RX_PW_P0-6	# = 0x00 0x00 0x00 0x00 0x00 0x00
EN_AA		 = 0xff
EN_RXADDR	# = 0xff
RF_CH		 = 0x00
RF_SETUP	# = 0x00
CONFIG		 = 0x00
DYNPD/FEATURE	# = 0x00 0x00
Data Rate	 = 1MBPS
Model		 = nRF24L01
CRC Length	 = Disabled
PA Power	 = PA_MIN

So.. I see a suspiciously large number of zeroes there. I guess comms with the module is not working!

Here are my connections (working on the simpler Nano 3 circuit first):

NRF24L01 --> Nano 3


Vcc --> 3V3
GND --> GND
CSN --> A6 A5
MO --> D11 (MOSI)
IRQ --> n/c
MI --> D12 (MISO)
SCK --> D13 (SCK)
CE --> D10

Can you suggest next step please?

Ps. I am running Arduino 1.0.1 on Ubuntu 12.10 64bit

OK, a schematic (of sorts ;-).

Try changing your CSN pin from A6 to another IO pin. On some model dev boards, A6 and A7 are analog input only. From memory, I think that's true of the Nano -- a quick search would confirm. (OK, just had a look, and indeed this is the case.)

A0-A5 can always be treated as normal digital IO pins.

pico:
A6 and A7 are analog input only.

I pulled a piece of green connecting wire out of my parts box, pushed one end into CSN and it reached across to... A6. "Fine" I told myself with total confidence, "any analog input can be used as a digital output".

Great catch. Will report back this evening.

Paul

OK then, I've changed A6 to A5. Output looks more promising:

Test connection to modules

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

I will now go back to my earlier sketches and see if anything's changed. Only because its easy, not because I have any particular attachment to that library.

...no joy.

I ran crofter's test sketch on the Pro Micro:

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

Looks OK.

So to keep everyone sweet I will now produce those schematics!

Schematic for the receiving circuit attached. If you don't mind I won't bother with the transmitter circuit, the connection list I gave above covers it.

Well, thanks to your help I am starting to get somewhere.

Here are the latest versions of my transmit sketch:

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

RF24 radio(10, A5);
const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL };


void setup() {
  
  radio.begin();
  radio.openWritingPipe(pipes[0]);
  radio.openReadingPipe(1,pipes[1]);
  radio.enableDynamicPayloads() ;
  radio.setAutoAck( true ) ;
  radio.setDataRate( RF24_250KBPS );
  radio.powerUp() ;

  Serial.begin(38400);
  
}

void loop() {
  while (Serial.available()) {
    char c = Serial.read();
    radio.write(&c, sizeof(char));
    //delay(250);
    Serial.write(c);
  }
}

and receive sketch:

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

#include <LiquidCrystal.h>

LiquidCrystal lcd(A3, A2, A1, A0, 10, 9);
RF24 radio(8,7);

const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL };


void setup() {

  radio.begin();
  radio.openWritingPipe(pipes[1]);
  radio.openReadingPipe(1,pipes[0]);
  radio.enableDynamicPayloads() ;
  radio.setAutoAck( true ) ;
  radio.setDataRate( RF24_250KBPS );
  radio.powerUp() ;
  radio.startListening();
  //radio.printDetails();


  lcd.begin(16, 2);
  lcd.print("Ready...");
  
}

void loop() {
  while (radio.available()) {
    char c;
    radio.read(&c, sizeof(char));
    if (c == 13) lcd.clear(); else lcd.write(c);
  }
}

I am getting some data received, but alot of it is getting lost. I tried reducing the data rate to 250KB/s but it did not seem to help at all. For example, I might type "Arduino" into the Serial Monitor, and the LCD displays "Adui" or "rdi" or just "d". Everything I type gets echoed back to Serial Monitor perfectly.

Can someone advise how to correct this please?

Thanks,

Paul

PaulRB:
I tried reducing the data rate to 250KB/s but it did not seem to help at all.

A basic thing you should realise is the modules you are using are the older nRF24L01, rather than the nRF24L01+ modules.

They are similar, and you can write code that will work for both, but there are differences too. One is that the older one doesn't support the 250Kbps air rate. So I'd recommend you stick to 1Mbps for all your testing. Also, see if you can find and download a datasheet for the older chip from Nordic -- you will need this (I'd really recommend having a read now just to get your head around the basic details of how these communicate with each other).

You've got SPI comms to the modules working on both boards, and limited comms between boards, so you are on your way. Apart from software issues, the final hardware aspect you will need to consider is the quality of your power supplied to the modules. The nRF2401/+ modules like their power supply nice and clean, otherwise you will get degraded performance -- sometimes drastically so.

Edit: Speaking to the above point, I don't see any decoupling caps on your schematic. I assume you don't have any for your transmit board either. You will need these -- depending on the quality (or lack of) of the 5V supply, it's quite possible you would be getting nothing successfully transmitted at all.

Also, you are using the 10 pin 5x2 connector modules. The "defacto" standard for 95% of the more modern modules are the 8 pin 4x2 modules (although there still a range of "oddball" variants out there). Given the extremely low cost of the low power modules, I'd recommend getting a pair of nRF24L01+ modules with the 4x2 header connection, just to make your life a little easier all around, and if you want to do things later on like upgrade one or both modules to the high power variants, etc. Actually, get a couple of pairs, to assist in testing and debugging. There are situations where quickly identifying a dead module will save wasting a lot of time.

As a quick test, I ran the following slightly modified versions of your code on an Uno and a Mega, both equipped with my RFX nRF24L01+ proto shields (see my sig for details), and running low power nRF24L01+ modules (8 pin style). A simple "type through" test works properly without dropping any characters, i.e., typing characters via the serial port on the tx sketch and viewing them being output on the serial port of the rx sketch.

So I'd suggest hardware is still most likely the area to focus your attention.

TX sketch:

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

#define CE 3
#define CSN 7

RF24 radio(CE, CSN);
const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL };


void setup() {
  
  Serial.begin(115200);
  radio.begin();
  radio.openWritingPipe(pipes[0]);
  radio.openReadingPipe(1,pipes[1]);
  radio.enableDynamicPayloads() ;
  radio.setAutoAck( true ) ;
  //radio.setDataRate( RF24_250KBPS );
  radio.setDataRate( RF24_1MBPS );
  radio.powerUp() ;  
}

void loop() {
  while (Serial.available()) {
    char c = Serial.read();
    radio.write(&c, sizeof(char));
    //delay(250);
    Serial.write(c);
  }
}

RX sketch:

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

//#include <LiquidCrystal.h>

#define CE 3
#define CSN 7

//LiquidCrystal lcd(A3, A2, A1, A0, 10, 9);
RF24 radio(CE, CSN);

const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL };


void setup() {

  Serial.begin(115200);
  radio.begin();
  radio.openWritingPipe(pipes[1]);
  radio.openReadingPipe(1,pipes[0]);
  radio.enableDynamicPayloads() ;
  radio.setAutoAck( true ) ;
  //radio.setDataRate( RF24_250KBPS );
  radio.setDataRate( RF24_1MBPS );
  radio.powerUp() ;
  radio.startListening();
  //radio.printDetails();

  //lcd.begin(16, 2);
  //lcd.print("Ready...");
  Serial.println("RX ready...");
}

void loop() {
  while (radio.available()) {
    char c;
    radio.read(&c, sizeof(char));
    //if (c == 13) lcd.clear(); else lcd.write(c);
    Serial.write(c);
  }
}

pico:
I don't see any decoupling caps on your schematic. I assume you don't have any for your transmit board either. Also, you are using the 10 pin 5x2 connector modules. I'd recommend getting a pair of nRF24L01+ modules with the 4x2 header connection,

Thanks Pico, you're right, I have assumed (probably foolishly) that the modules have those built-in. I will experiment with adding one or more 0.1uF suppression caps to to both boards. Also I have read advice that peak current draw might exceed what's available, so will also try adding 10uF reservoirs also.

I did buy in haste (while I was placing an order with a Chinese eBay supplier) and did not realise the difference between the "+" and non-"+" varieties. If I can't get the performance I need with these units, I will certainly be following your advice (and will do anyway for future purchases).

Thanks again! Will update later with progress.

Paul

Another thing: you might want to put an extra diode in series to drop the voltage from 5V. At a nominal 0.7V forward drop per diode, you're only just within the range of up to 3.6V on Vcc for the nRF24L01+ modules. And the forward voltage drop will be less than 0.7V for small current loads anyway, so chances are you are outside spec. The nRF24L01+ will operate happily at ~2.9V, so I think that's be a more forgiving range to aim for.

Better still get a low drop 3.3V voltage regulator, like an LD1117v33. Works very well for this application.

Edit: Data sheet says the max Vcc is actually 3.3V if the data inputs > 3.6V. So you will be outside spec. in any case with only two diodes.

Hi pico,

Had some fun this evening testing the range of these modules around the house. The various caps do seem to have sorted out the lost data problem. Have also added the 3rd diode. Didn't seem to make much difference but better safe than sorry.

Transmission in the same room seems 100% reliable. Two rooms away on same floor, also 100%, even though one of those walls is 0.5m thick stone. Downstairs and two rooms away, only very occasional characters received. Exactly the same range as my 'n' wifi router in fact. I need two routers in my house, connected by cat5 through that thick stone wall. Its a converted barn (around 200 yrs old) and that wall was originally the outside wall, the part beyond it was build in the 1980s.

However, a strange thing happens at times. The circuits get into a state where it is as though the keystrokes are going through a FIFO buffer, only 2 or 3 characters long. In other words, the received data gets 2 or 3 characters behind the transmitted data. These characters are not lost, they do reliably appear when more characters are sent. But then those new characters don't get received until yet more characters are sent. As you have seen, there's nothing in my sketches to implement a FIFO buffer.

Concluded that this range will probably not be good enough for the project I had in mind. For that, the signal must pass through the thick stone wall and then another 20m (unobstructed).

In your opinion, if I get some of the newer "+", but still low power, will they have the range? The 250KBS speed should be plenty, there won't be much volume of data to transmit.

Thanks,

Paul

PaulRB:
Hi pico,

Had some fun this evening testing the range of these modules around the house. The various caps do seem to have sorted out the lost data problem. Have also added the 3rd diode. Didn't seem to make much difference but better safe than sorry.

I'm not very surprised -- power supply problems are probably the single most common stumbling block for successfully deploying these modules. The problem is, they kinda, sorta work if given bad power, and people assume the limited range and general performance they see are down to the limitations of the modules, rather than the fact they aren't operating anywhere near their potential.

PaulRB:
Transmission in the same room seems 100% reliable. Two rooms away on same floor, also 100%, even though one of those walls is 0.5m thick stone. Downstairs and two rooms away, only very occasional characters received. Exactly the same range as my 'n' wifi router in fact. I need two routers in my house, connected by cat5 through that thick stone wall. Its a converted barn (around 200 yrs old) and that wall was originally the outside wall, the part beyond it was build in the 1980s.

That all sounds pretty much as good as can be expected.

PaulRB:
However, a strange thing happens at times. The circuits get into a state where it is as though the keystrokes are going through a FIFO buffer, only 2 or 3 characters long. In other words, the received data gets 2 or 3 characters behind the transmitted data. These characters are not lost, they do reliably appear when more characters are sent. But then those new characters don't get received until yet more characters are sent. As you have seen, there's nothing in my sketches to implement a FIFO buffer.

That may be an artifact of the demo transmit sketch. I didn't mention it earlier, because it was just for testing, but it's really inefficient, sending only character per packet (which is wasteful, as a packet can hold up to 32 bytes).

Further, there are three TX packet buffers (which are FIFO). If you try to send a packet before the last one has finished sending, it will get put in one of the buffers (there can multiple retries with sending using AA mode, so it can take longer than expected for a packet to get through). If the library doesn't recognise the situation and check for non-empty TX buffers after an xmit, they will languish until the next xmit... and you will always be a buffer (or two) behind!

Hope that makes sense. It's in the datasheet (you do have a datasheet now, don't you?) So it sounds like an inefficient sketch design meets a library bug.

To make the sending more reliable, I'd buffer your characters (up to 32 bytes, or a , whichever comes first) and send the string as one packet, rather than character at a time. This will likely avoid the FIFO buffering bug. Alternatively, you can explicitly check for a non-empyty TX FIFO buffers at the end of each xmit yourself, and continue to xmit until the TX FIFO reads empty (datasheet will tell you which register to read to get TX FIFO status.) So fix a bug, or work around it -- up to you!

PaulRB:
Concluded that this range will probably not be good enough for the project I had in mind. For that, the signal must pass through the thick stone wall and then another 20m (unobstructed).

In your opinion, if I get some of the newer "+", but still low power, will they have the range? The 250KBS speed should be plenty, there won't be much volume of data to transmit.

250kbps might do the trick to get enough extra range. I'd give it a try since the low power modules are so cheap, but it may be that you will need to upgrade to at least one higher power module, maybe two.

Let us know how you get on with the sketch and/or lib adjustments.

pico:
people assume the limited range and general performance they see are down to the limitations of the modules, rather than the fact they aren't operating anywhere near their potential.

So could I still be in that situation, do you think? During testing, the transmit circuit was powered by the 3.3V output on the Nano 3, which in turn is powered by USB power from desktop PC. The breadboard also had a 0.1uF and 10uF accross the 3.3V power rails. The Receive circuit was powered via the Pro Micro's 5V regulator, reduced by the 3 diodes down to a little less than 3.3V. The Pro Micro being powered from 4 x AA NiMh, freshly charged. That breadboard also equipped with 0.1uF and 10uF caps on the 5V rails. (I don't have a 'scope to check for short term dips on the power rails.)

pico:
there are three TX packet buffers (which are FIFO). If you try to send a packet before the last one has finished sending, it will get put in one of the buffers... It's in the datasheet (you do have a datasheet now, don't you?

Well... I downloaded the data sheet... I will get around to reading at least some of it, once I am convinced these are the right modules for my project.

pico:
250kbps might do the trick to get enough extra range... but it may be that you will need to upgrade to at least one higher power module, maybe two.

So, upgrading just one of a pair to higher power should give some range improvements, even if the other is low power? That's handy to know. I suppose if the more expensive module has a more sensitive receiver circuit as well as a higher power transmit circuit, it must be able to make up for the weaker transmit power of the cheaper module, to a degree. Good to know.

Thanks again pico (Mark, is it?)