I've got a project which requires short-range communication without WiFi available, so I'm trying to use some nRF24L01 transceivers to make this happen.
I'm using an Arduino Uno to transmit data, and a Raspberry Pi 4 to receive that data, but so far the Pi has not received a single message. I've been through a variety of tutorials and packages/libraries at this point with absolutely no success.
I'm a seasoned software developer, but not as experienced with the Arduino side of things.
Here is the configuration:
Arduino:
| nrf24 | arduino |
|---|---|
| Vin | 3V3 |
| GND | GND |
| CE | Pin 9 |
| CNS | Pin 10 |
| MOSI | Pin 11 |
| MISO | Pin 12 |
| SCK | Pin 13 |
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include "printf.h"
RF24 radio(9, 10);
void setup() {
printf_begin();
Serial.begin(9600);
radio.begin();
radio.setChannel(0x76);
const uint64_t address = 0xfd7dfdfdfd;
radio.setPALevel(RF24_PA_MIN);
radio.setCRCLength(RF24_CRC_16);
radio.enableDynamicPayloads();
radio.enableAckPayload();
radio.setDataRate(RF24_1MBPS);
radio.openWritingPipe(address);
radio.stopListening();
radio.printDetails();
}
void loop() {
bool sendResult;
if (radio.available()){
Serial.println("Radio is available");
} else {
Serial.println("Radio is unavailable");
}
char text[32] = "Testeroni";
sendResult = radio.write(&text, sizeof(text));
if (sendResult) {
Serial.println("Message sent");
} else {
Serial.println("Message not sent");
}
delay(1000);
}
Pi 4:
Using the lib_nrf24 package.
SPI is enabled:
$ stat /dev/spidev0.0
File: /dev/spidev0.0
Size: 0 Blocks: 0 IO Block: 4096 character special file
Device: 5h/5d Inode: 420 Links: 1 Device type: 99,0
Access: (0660/crw-rw----) Uid: ( 0/ root) Gid: ( 999/ spi)
Access: 2022-04-02 16:16:46.749999997 -0500
Modify: 2022-04-02 16:16:46.749999997 -0500
Change: 2022-04-02 16:16:46.749999997 -0500
Birth: -
| nrf24 | pi/GPIO |
|---|---|
| Vin | Pin 17 / 3V3 |
| GND | Pin 20 / GND |
| CE | Pin 22 / GPIO 25 |
| CNS | Pin 24 / GPIO 8 / SPI0_CE0_N |
| MOSI | Pin 19 / GPIO 10 / SPI0_MOSI |
| MISO | Pin 21 / GPIO 9 / SPI0_MISO |
| SCK | Pin 23 / GPIO 11 / SPI0_CLK |
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
import time
import spidev
from lib_nrf24 import NRF24
radio = NRF24(GPIO, spidev.SpiDev())
radio.begin(0, 7)
radio.setRetries(15, 15)
radio.setChannel(0x76)
radio.setDataRate(NRF24.BR_1MBPS)
radio.setPALevel(NRF24.PA_MIN)
radio.setCRCLength(NRF24.CRC_8)
radio.setAutoAck(True)
radio.enableDynamicPayloads()
radio.enableAckPayload()
radio.openReadingPipe(0, [0xfd, 0x7d, 0xfd, 0xfd, 0xfd])
radio.startListening()
radio.stopListening()
radio.printDetails()
radio.startListening()
c = 1
while True:
akpl_buf = [c,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8]
while not radio.available([0]):
time.sleep(10000/1000000.0)
recv_buffer = []
radio.read(recv_buffer, radio.getDynamicPayloadSize())
if recv_buffer:
print(f'Received: {recv_buffer}')
c += 1
if c&1 == 0:
radio.writeAckPayload(1, akpl_buf, len(akpl_buf))
time.sleep(1)
Startup
I begin by starting the Raspberry Pi Receiver:
$ sudo python library_listener.py
/home/pokeybill/lib_nrf24.py:377: RuntimeWarning: This channel is already in use, continuing anyway. Use GPIO.setwarnings(False) to disable warnings.
self.GPIO.setup(self.ce_pin, self.GPIO.OUT)
STATUS = 0x03 RX_DR=0 TX_DS=0 MAX_RT=0 RX_P_NO=1 TX_FULL=1
RX_ADDR_P0-1 =
0xffdfffffff 0xf87878f8f8
RX_ADDR_P2-5 =
0xf8
0xf9
0xf9
0xf9
TX_ADDR =
0xfdfdfdfdfd
RX_PW_P0-6 =
0x81
0x80
0x80
0x80
0x80
0xc0
EN_AA =
0x8f
EN_RXADDR =
0xc0
RF_CH =
0x9f
RF_SETUP =
0xff
CONFIG =
0x98
DYNPD/FEATURE =
0x83
0x81
Data Rate = 1MBPS
Model = nRF24L01
CRC Length = 8 bits
PA Power = PA_HIGH
Received: [128, 0, 0, 0, 0]
Then I fire up the Arduino Uno, here is the serial output:
STATUS = 0x0e RX_DR=0 TX_DS=0 MAX_RT=0 RX_P_NO=7 TX_FULL=0
RX_ADDR_P0-1 = 0xfd7dfdfdfd 0x0104030201
RX_ADDR_P2-5 = 0xc3 0xc4 0xc5 0xc6
TX_ADDR = 0xfd7dfdfdfd
RX_PW_P0-6 = 0x20 0x20 0x20 0x20 0x20 0x20
EN_AA = 0x3f
EN_RXADDR = 0x03
RF_CH = 0x76
RF_SETUP = 0x01
CONFIG = 0x0a
DYNPD/FEATURE = 0x3f 0x06
Data Rate = 1MBPS
Model = nRF24L01+
CRC Length = 8 bits
PA Power = PA_MIN
Radio is unavailable
Message not sent
Immediately I notice the warning:
RuntimeWarning: This channel is already in use, continuing anyway. Use GPIO.setwarnings(False) to disable warnings.
self.GPIO.setup(self.ce_pin, self.GPIO.OUT)
however, it seems like no matter what I do, I always get this warning. I've tried rebooting the pi multiple times and explicitly calling GPIO.cleanup() without any joy.
Also, it seems like no matter what I use for the pipe addresses in the Raspberry Pi code, they do not match up with the receiver configuration I see.
The arduino radio.available() call never returns true, and the radio.write call is never acknowledged.
The pi occasionally receives random noise, but never receives a message from the arduino. The pi also seems to have an RF_CH=0x1f when I explicitly set the channel to 0x76 in the code. To me it feels like I'm missing something with the Pi side of things, but I really don't know enough to understand what I'm missing here.
Its possible the information required to get to the bottom of this is in the radio detail output, but I'm just not sure where to look. I've tried varying CRC length, PA power, and the write/read pipe address - no adjustments to these values have made any difference.