NRF24L01 unreliability

Posted on
  • Hi!

    I'm testing communication between two espruinos with NRF24L01+, one should be a weather station on the outside and the other one the recipient on the inside.

    They work fine if close to each other but the longer the first one is sending data, the more noise gets mixed into the datastream.

    Also when I move them further apart, the noise starts right after the first data packe. Only the first package is sent correctly and all following packages get a lot of noise.

    I am not sure whats happening here. Is it possible that using other stuff on the sender (a TSL2561 and a DHT22) could influence the data quality a lot? To me it looks like it does, because the first data package is sent perfectly before anything is read from both sensors but once I'm reading data from them, the data gets messed up.

    Does anybody has any idea on whats happening?


  • Shortly after posting this, I realized that the NRF is sending data in packets of max. 32bytes and my payload is bigger (~128bytes). I quickly reduced the sending part to use smaller data packets and now more packets are getting thru in the beginning but at some point its still just "noise".

  • That is strange - I guess there should be a check in the module for packet size (although I thought it automatically split longer packets into several short ones).

    It has been suggested that you could add a 0.1uF tant/ceramic capacitor across the power pins of the NRF module to help with unreliability - but I don't think that is the problem here - the modules have a CRC check I believe, so if you're receiving bad data it's either getting it from another NRF module (not yours), or the wrong data is being sent in the first place.

    Is it possible that you're not sending strings, but arrays? I imagine the NRF module could get a bit confused there as I think it is designed to only handle strings.

  • Thank you, Gordon!

    I already added a capacitor on both, that didn't change much.

    I kept testing last night with the transmissions and I think the problem is maybe in combination with the TSL readings. By reducing the package size I got it to send good data every now and then but whenever a reading from the TSL2561 was scheduled, the data package gets still messed up.

    Its like trying to send data within callbacks after reading from the TSL does mess it up. After 30 or so more seconds it works again.

    I am 100% sure that I am sending strings and I also convert all readings with Math.round() to make it impossible to have junk in my values from using possibly faulty readouts.

    Tonight I will try to remove the TSL and maybe don't send data within the callbacks.

  • Hmm - have you tried sending the same data (just a packet saying 'Hello World' while also reading from the TSL2561? it might help to narrow it down).

  • I did some long running sending tests with different situations:

    1. Sending just from within the DHT callback > package loss wasn't too big and was still sending data after 12hrs
    2. Sending data just from within the TSL callbacks > package loss starts very fast and moved to sending nearly 100% junk after a few hours
    3. Sending data with an interval, separate from the callbacks > some package loss and was still sending after 12hrs
    4. Just sending "Hello World" without using doing any sensor readings in an interval > some package loss and still sending after while
    5. Sending in shorter/longer intervals (every 5seconds vs. every minute) > less package loss on smaller intervals and nearly no "noise" in the received data packages, over time the noise did not increase while using longer intervals resulted in an increased loss of data/more noise in the data packages over time

    What I learned from these tests, is that I should send data not within callbacks but rather in an independent scope/interval outside of all the callbacks.

    I tried to fine tune the sending process by:

    1. using different data rates, which didn't change a lot
    2. using .setTXPower(3) to maybe send a stronger signal, which didn't change anything as far as I can tell (while setting it to 0 resulted in no data sent anymore)
    3. re-sending the data if .sendString() fails for some reason, which helps a lot but results in strange results. Failed sendings produce the error message TX not received 30 but still send some part of the data.

    What I've seen in the very beginning, became very strange and repeatable when I re-sent data that was not successfully sent. Data packages arrived combined at the target node.

    For example:

    Sending Hello World sometimes arrived as HelloSªorldHello World or WorSªiQ¦llo World or WorSªiQ¦llo WorldrS¶‘=Q¦llo World.
    Which looks like sent data is combined at the recipients end and the data packages are not correctly differentiated when received. It's maybe the NULL or EOT Byte thats not correctly received sometimes, leading to merged data packages.

    I am using a slightly modified version of the example code from the website at the recipients side which seems to be very stable:

      var dataLine = "";
      setInterval(function() {
        while (nrf.getDataPipe() !== undefined) {
          var data = nrf.getData();
          for (var i in data) {
            var ch = data[i];
            if ((ch===0 || ch===4) && dataLine!=="") {
              status.lastNrfLine = dataLine;
              // remove noise in the beginning of the line
              if ( dataLine.indexOf('{') > 0 ) {
                dataLine = dataLine.substr(dataLine.indexOf('{'));
              // remove noise at the end of the line
              if ( (dataLine.lastIndexOf('}')+1) != dataLine.length ) {
                dataLine = dataLine.substr(0, dataLine.lastIndexOf('}') + 1);
              if ( dataLine.substr(0,1) == "{" && dataLine.substr(-1) == "}" ) {
                status.lastNrfPacket = dataLine;
                try {
                  // replace -1 values because JSON.parse fails on them
                  while ( dataLine.indexOf(":-1") >= 0 ) {
                    dataLine = dataLine.replace(':-1', ':\"-1\"');
                catch (e) {
                  // ignore failed packets...
              dataLine = "";
            } else if (ch!==0 && ch!==4 && ch >= 32) { // 0 = NULL, 4 = EOT, <32 = all command codes
              dataLine += String.fromCharCode(ch);
      }, 50);

    So much from my NRF-adventures, I think, now I can get to a stable solution with an independent interval that sends the data in the global scope instead of sending data within the callback-scopes. I also think that I will find out more about the real problems with further testing and networking more nodes.

    Is there anywhere I can lookup the error codes for the sending? What doesTX not received 30 mean?


  • The number after 'not received' is the value of the status register, so you'd have to look in the NRF24's datasheet I'm afraid. The actual code that interfaces to the NRF24 is here

    The NRF24's have 2-way communication - they send a packet and then get an 'Ack' packet back. It's if they don't get an acknowledge back that they give you the error... So if the 'final' packet is missing then it's not surprising you'd get remnants of the first packet I guess.

    How far away are the modules? It's possible that they really are having trouble communicating - 2.4Ghz turns out to be pretty bad at getting through walls... I can't get the modules to work reliably from one side of my house to the other.

    Another solution might be to intentionally make sure you only send self-contained 32 character packets. At least that way, if one got lost you would just lose it, and it wouldn't corrupt other packets.

  • I've seen that in the code, Gordon, but I can not find a reference list of the codes ( looked at­RF2401rev1_1.pdf ).

    But I also got it stable with a small trick last night.
    I've put both sensors power inputs on an analog output which provides 3.3V and I turn them on just 500ms and initialize the connections again before I am going to read from them, then I turn the signal off, when I'm done.

    Suddenly I am still receiving data (with sometimes a little noise). yay!
    Btw. they are currently 4 meters apart with one wall in between, this is the maximum I've managed. This is where I will want to use a pico in the future as a repeating node :-)

    Thanks a lot for your time and input!

    I can't put my finger on it, but I think its a performance issue that comes up after a while which makes the sending part choke on its data. The issues must be within the TSL module or the I2C connection because just reading from it influences the NRF sending and also freezes the terminal eventually.

    Thanks again and have a great weekend,

  • Try­ownload/2726/34069/file/nRF24L01P_Produc­t_Specification_1_0.pdf page 59

    It's not the most useful number to know though!

    Glad you got it working, but it's strange that you're having those issues with lockups though. Are you using an up to date firmware (1v71)?

    1 Attachment

    • Screenshot from 2014-12-01 10:07:28.png
  • Yes, I am working on 1v71 – thanks a lot for pointing to the right page! :)

    I'm now going to post the collected data to a nodejs processing server which will create some nice stats in the future and serves as the first step in my improved home automation project :))

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview

NRF24L01 unreliability

Posted by Avatar for favo @favo