[solved] Yet another nRF24L01+ issue/problem

Edit: Solution For the curious, the problem all along was just that the 3.3v supply pins on the RPi can’t source enough current to properly drive the RF24+. I switched the RF24 to using an external power supply (itself powered by an RPi USB port) and it started working immediately.

TL;DR: Are there any specific “gotcha’s” when using this radio to communicate between a Pi (3B+) and an Arduino, vs between multiple Arduinos? With Nanos acting as transmitters, the exact same code works fine on the Uno but not on the Pi.

Long version: I have a pile of Arduino’s here (9 LAFVIN Nanos and an Elegoo Uno R3), and a single Canakit Raspberry Pi 3B+. I also have a handful of nRF24L01+ radios – authentic devices from Makerfire, not clones.

I have two Nanos setup with RF24s sending sensor data once a second, and the Uno running a sketch that displays the received data and displays it on the 16x2 LCD, along with a count of how many messages it’s received from each device. This has been working flawlessly for a few days now. All of the devices are setup with the same address, and using pipe 0. The init code on all three of them is identical:

  radio.begin();
  radio.setPALevel(RF24_PA_LOW); // power level
  radio.setChannel(RF_CHANNEL);
  radio.setDataRate(RF_RATE);
  radio.openWritingPipe(address);
  radio.openReadingPipe(0, address);
  radio.startListening();

The Nanos simply sleep for a second then turn on an LED, read their sensor data, send it with radio.write(data, size, true), then turn off their LED. The Uno sits in a loop simply checking radio.available(), and reading and printing the data when it’s available. It doesn’t send anything, at least not by my instruction. I only recently found out about the ACK/Multicast option.

Again, let me reiterate, that the above works perfectly for tens of thousands of messages with no issues, transmitting from the Nanos to the Uno. However, taking exactly the same code and compiling and running it on my Pi results in no messages being received. At first I thought this was due to the ACK thing, once I found out about that, so I turned off the Uno (which was still logging messages) and restarted the Pi, to no avail.

Eventually I found that even though both systems are using the same library (tmrh20 v1.3.4), the Pi’s radio.begin() apparently issues a different setup command than the one used on the Arduinos. For example, all the Arduino radios were initialized to channel 76 (before I added the call to setChannel()) while the Pi was initialized to channel 0 according to the information from radio.printDetails() which you can see here:

================ SPI Configuration ================
CSN Pin          = CE0 (PI Hardware Driven)
CE Pin           = Custom GPIO17
Clock Speed      = 8 Mhz
================ NRF Configuration ================
STATUS           = 0x0e RX_DR=0 TX_DS=0 MAX_RT=0 RX_P_NO=7 TX_FULL=0
RX_ADDR_P0-1     = 0x0504030201 0xc2c2c2c2c2
RX_ADDR_P2-5     = 0xc3 0xc4 0xc5 0xc6
TX_ADDR          = 0x0504030201
RX_PW_P0-6       = 0x20 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

This a full sketch for the Nano doing temperature sensing (I have different sensors on different Nanos):

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


#define DHT_TYPE DHT11

#define PIN_DHT  2
#define PIN_CE   3
#define PIN_CSN  4
#define PIN_LED  5 // tx LED

typedef enum {
  UNK,
  UNK_F,
  UNK_L,
  UNK_UL,
  SENS_TEMP,
  SENS_ACCEL,
  SENS_WLEVEL
} SensorType;

typedef struct SensorReports {
  uint8_t address[5];
  unsigned int battery_level;
  unsigned int voltage;
  SensorType sensor_type;
  union {
    unsigned long data_ul;
    long data_l;
    float data_f;
  };
} SensorReport;


uint8_t address[] = {0x01, 0x02, 0x03, 0x04, 0x05};

RF24 radio(PIN_CE, PIN_CSN);
DHT dht(PIN_DHT, DHT_TYPE);

void copy(uint8_t* src, uint8_t* dst, int len) {
  memcpy(dst, src, sizeof(src[0])*len);
}

void setup() {
  pinMode(PIN_LED, OUTPUT);

  digitalWrite(PIN_LED, LOW);

  dht.begin();
  
  radio.begin();
  radio.setPALevel(RF24_PA_LOW); // power level
  radio.openWritingPipe(address);
  radio.openReadingPipe(0, address);
  radio.startListening();
}

void loop() {
  SensorReport report;

  // float temp = dht.readTemperature(false);
  copy(address, report.address, 5);
  report.battery_level = 0;
  report.voltage = 0;
  report.sensor_type = SENS_TEMP;
  report.data_f = dht.readTemperature(false);
  
  digitalWrite(PIN_LED, HIGH);
  radio.stopListening();
  radio.write(&report, sizeof(SensorReport), true);
  radio.startListening();
  digitalWrite(PIN_LED, LOW);
  delay(1000);
}

And the server code:

#include <stdlib.h>
#include <RF24/RF24.h>

#define PIN_CE   RPI_BPLUS_GPIO_J8_11
#define PIN_CSN  RPI_BPLUS_GPIO_J8_24
#define RF_CHANNEL 76
#define RF_RATE RF24_1MBPS

typedef enum {
  UNK,
  UNK_F,
  UNK_L,
  UNK_UL,
  SENS_TEMP,
  SENS_ACCEL,
  SENS_WLEVEL
} SensorType;

typedef struct SensorReports {
  uint8_t address[5];
  unsigned int battery_level;
  unsigned int voltage;
  SensorType sensor_type;
  union {
    unsigned long data_ul;
    long data_l;
    float data_f;
  };
} SensorReport;


RF24 radio(PIN_CE, PIN_CSN);

uint8_t address[] = {0x01, 0x02, 0x03, 0x04, 0x05};

int main(int argc, char** argv)
{
  SensorReport report;
  unsigned long rxcounter1 = 0;
  unsigned long rxcounter2 = 0;

  radio.begin();
  radio.setPALevel(RF24_PA_LOW);
  radio.setChannel(RF_CHANNEL);
  radio.setDataRate(RF_RATE);
  radio.openWritingPipe(address);
  radio.openReadingPipe(0, address);
  radio.printDetails();
  radio.startListening();

  if (!radio.isChipConnected()) {
    printf("No chip!\n");
    return 0;
  }

  printf("Entering listening loop\n");
  while(1) {
    while (radio.available()) {
      radio.read(&report, sizeof(SensorReport));
      printf("Got message (%d)\n", report.sensor_type);

      switch (report.sensor_type) {
        case SENS_TEMP:
          rxcounter1++;
          printf("%.1f (%lu)\n", report.data_f, rxcounter1);
        break;

        case SENS_WLEVEL:
          rxcounter2++;
          printf("%luW (%lu)\n", report.data_ul, rxcounter2);
        break;
      }
    }
    delay(250);
  }

  return 0;
}

This server code works perfectly on the Uno, replacing the printf’s with console logs or prints to the LCD, but when running on the Pi, it seems to never receive any messages. Any help on why the Pi is behaving differently from the Uno would be appreciated!

It's not clear from your Post whether you have created a short RPi program and a short Arduino program to learn how to communicate between the RPI and an Arduino. I don't have any RPi myself, but that seems to me an essential first step.

My suggestion is to set up two Arduinos using the first (simplest) example in this Simple nRF24L01+ Tutorial.

When that is working then adapt the code for the Rx Arduino so it should work on the RPi and get that working between the RPI as Rx and the Tx Arduino

...R

PS ... if you do get a slight variant of my example working with the RPi I would appreciate it if you would post the working RPi code.

I have a simpler version now demonstrating the problem. I cut this down to about the minimum needed for it to work between the Arduino’s and demonstrate the issue. I thought there might be some architecture related sizing issues in my structure so I eliminated that as well.

Uno (receiver) sketch:

#include <LiquidCrystal.h>
#include <RF24.h>

#define PIN_CE   3
#define PIN_CSN  4
#define RF_CHANNEL 0x4C
#define RF_RATE RF24_1MBPS

uint64_t address = 0x0000000000000001;
uint8_t rxcount = 0;
char line[17];

//            lcd(RS, EN, D4, D5, D6, D7)
LiquidCrystal lcd(5, 6, 7, 8, 9, 10);
RF24 radio(PIN_CE, PIN_CSN);

void setup() {
  lcd.begin(16, 2);
  radio.begin();
  radio.setPALevel(RF24_PA_LOW); // power level
  radio.setChannel(RF_CHANNEL);
  radio.setDataRate(RF_RATE);
  radio.openReadingPipe(0, address);
  radio.startListening();

  lcd.clear();
  sprintf(line, "Running");
  lcd.setCursor(0, 0);
  lcd.print(line);
}

void loop() {
  while (radio.available()) {
    radio.read(&rxcount, sizeof(uint8_t));

    lcd.clear();
    sprintf(line, "Looping");
    lcd.setCursor(0, 0);
    lcd.print(line);

    sprintf(line, "0x%02x rxd", rxcount);
    lcd.setCursor(0, 1);
    lcd.print(line);
  }
}

Nano (transmitter) sketch

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

#define PIN_CE   3
#define PIN_CSN  4
#define PIN_LED  5 // tx LED
#define RF_CHANNEL 0x4C
#define RF_RATE RF24_1MBPS

uint64_t address = 0x0000000000000001;
uint8_t foo = 0;

RF24 radio(PIN_CE, PIN_CSN);

void setup() {
  pinMode(PIN_LED, OUTPUT);

  digitalWrite(PIN_LED, LOW);

  radio.begin();
  radio.setPALevel(RF24_PA_LOW); // power level
  radio.setChannel(RF_CHANNEL);
  radio.setDataRate(RF_RATE);
  radio.openWritingPipe(address);
}

void loop() {
  digitalWrite(PIN_LED, HIGH);
  foo = foo + 1;
  radio.write(&foo, sizeof(uint8_t), true);
  digitalWrite(PIN_LED, LOW);
  delay(1000);
}

And finally the C program running on the pi.

#include <stdlib.h>
#include <stdint.h>
#include <RF24/RF24.h>

#define PIN_CE   RPI_BPLUS_GPIO_J8_11
#define PIN_CSN  RPI_BPLUS_GPIO_J8_24
#define RF_CHANNEL 0x4C
#define RF_RATE RF24_1MBPS

RF24 radio(PIN_CE, PIN_CSN); //, BCM2835_SPI_CLOCK_DIVIDER_64);

uint64_t address = 0x0000000000000001;
uint8_t rxcount = 0;
char line[17];

int main(int argc, char** argv)
{
  radio.begin();
  radio.setPALevel(RF24_PA_LOW);
  radio.setChannel(RF_CHANNEL);
  radio.setDataRate(RF_RATE);
  radio.openReadingPipe(0, address);
  radio.printDetails();
  radio.startListening();

  if (!radio.isChipConnected()) {
    printf("No chip!\n");
    return 0;
  }

  printf("Entering listening loop\n");
  while(1) {
    while (radio.available()) {
      radio.read(&rxcount, sizeof(uint8_t));
      printf("0x%02x rxd\n", rxcount);
    }
  }

  return 0;
}

One weird thing of note… the Pi does occasionally enter the “radio.available()” block, but it’s very rare, and it never has actual data in it that I can discern, simply printing “0x01” each time. I thought there might be a clocking issue with SPI or something, so I’ve tried several different speeds there to no avail. The SPI interface does seem to be working though, or I’d expect garbage/no data from the printDetails() method.

This is really confusing and frustrating :slight_smile:

Robin2:
It’s not clear from your Post whether you have created a short RPi program and a short Arduino program to learn how to communicate between the RPI and an Arduino.

I don’t have any RPi myself, but that seems to me an essential first step.

I agree, and that’s actually what I’m trying to do here, now, in my 2nd post. I can’t think of something simpler than just sending a single byte from one to the other.

PS … if you do get a slight variant of my example working with the RPi I would appreciate it if you would post the working RPi code.

I certainly will.

The code I just posted should work. It’s C on both sides, I just copy/pasted from the Arduino sketch to the Pi .c file and made the minimum required adjustments. Stuff like adding the PIN definitions for the RPi, switching the LCD code to printf(), etc. You can see between the two that there’s no real difference.

Hopefully somebody will come along who has experience of doing this with an RPi. Maybe it would help if you edit your Original Post and change the title to "Need help to get Arduino and RaspberryPi communicating with nRF24L01+"

I was rather hoping you were using Python on the Pi but that's not relevant to your problem.

...R

I had a bug in the C code for the RPi and it wasn't actually printing the value in the printf() call. I corrected that and now it seems like it's getting some sort of data, but it didn't always trigger.

On a whim I decided to try an external power supply for the RF24 and, lo and behold, it's working fine now. Apparently the 3.3v header on the RPi can't source enough current for the RF24.

Mark it solved, and Robin, feel free to take the above code I posted and use it in your examples.

alzee:
Mark it solved, and Robin, feel free to take the above code I posted and use it in your examples.

Thanks.

I will bookmark this Thread in case it may be useful

...R