Finally, the nRF24 devices are talking to each other! It was a bit of a road trip. One thing to note is the importance of the status byte, and the status screen. A hex 0x00 in the status byte, and lots of zeros on the printDetail() screen is a pretty good indicator that your SPI is not operational, and you’re not talking to the transceiver. More on this issue follows …
I’ve wired an nRF24 board into both the “yellow box” server (an Odroid/C1+ SBC based box), and the original “homemade tablet” – which is an Odroid/C1 (original model) based computer. The communication was successful! There were a few wrinkles, which needed to be ironed out – so I’ll put a more detailed description here than I normally do when things are simple. Especially, there were external hardware additions needed, and I’ve listed those at the bottom of this page (actually, those can be circumvented by a device tree file change (detailed on the next page of this post).
To start with, I used git to obtain the nRF24 library and example programs:
- git clone https://github.com/TMRh20/RF24.git
- cd RF24
- make # This should result in librf24.so.1.16 being built in the directory.
- make install
The library should compile without modification, using the official Ubuntu Linux image for the Odroid/C1 SBC. Subsequently to installing the RF24 library, I built the example programs that run against that library.
But, before compiling them, I changed a line in each of the example programs, wherein the GPIO pin for the SPI CE pin is defined:
// Setup for ARM(Linux) devices using spidev (default “/dev/spidev1.0” )
I “uncommented” the line shown above, and put a comment (//) in front of the following line:
The last line would set the GPIO/CE for the Raspberry Pi, which we’re not using in this case. On the Odroid, we’re using physical pin 15 for SPI CE, which is called as described. It is assumed that the wiringpi programs have already been compiled (see the previous page of this thread for info on that). Immediately ahead of the “printDetails” call in the pingpair_dyn.cpp source code file, I needed to put additional lines:
Note: the radio power can be set as high as the value RF24_PA_HIGH and still be within unlicensed band limits. IIRC, the RF24_PA_MAX value puts the device over the limit (barely). When possible, the following setAutoAck() should probably be used with a true argument in most cases, because it enables packet acknowledgement in the nRF24 hardware. Having packets unacknowledged is unreliable. If the nRF24 hardware Auto-Ack is not used for some reason (like my reason, which is multicasting) – then a payload based acknowledgement protocol has to be devised.
The original github.com/TMRH20/RF24/ examples_linux/ pingpair_dyn.cpp source didn’t have any setChannel() or setPALevel() (power) or setAutoAck() function calls. I’m not sure what the default values are, if they are not set explicitly. Pingpair_dyn is the only file I’ve messed with. In it, the added lines seemed to work OK, but I’m not using hardware packet acknowledgement (again – because I’ve set it to false). Thus, I am forced to do the acks in the software I write. Otherwise, it won’t be very reliable.
I have no idea how reliable the hardware ack is. Probably it does great. Other programs in the examples directory may rely on setting setAutoAck(true); AFAIK the pingpair_dyn program should work better with auto-acknowledgement set to true. For some reason it did not work at all for me. It’s probably my problem, and not the nRF24’s.
The idea of a hardware based packet acknowledgement is to increase reliability. I don’t know how well the nRF24 does this. Due to the nRF24 not using source addresses, auto-ack (relative to my unconfirmed information) cannot be used with multicasting, which is the way I’ll probably be using these devices. That is not necessarily a big issue for me, as I can put a reliable transport protocol in the payload, if I like. I already have one partially devised.
According to http://tmrh20.github.io/RF24Network_Dev/Tuning.html – the nRF24 “auto-ack” is an on-chip hardware based acknowledgement mechanism. I’ll be using so many devices that I’ll probably need to number packets for reconstruction myself, add checksums and do other things to build some sort of payload based reliable transport. I’d probably use the hardware auto-ack if I could in my circumstance. The github has information on this aspect, and it defines a tree/parent/child setup (up to 5 children) that is apparently built into the nRF24. I’m looking at more than five children without even counting sensors.
The power level may need to be raised, depending on application. And, the retries (setRetries();) value could require some adjustment, depending upon circumstances. The channel number may need to be reselected to find a spot with less interference. The competition (regular WiFi) is much more powerful than the nRF24, such that it might interfere with communication. Most of these nRD24 parameters have default values, so a decision is made even if it isn’t. Sometimes, the defaults may be OK for a particular application. All this needs to be checked out. I haven’t looked at every detail of this.
The wiringpi source code that I used is a fork of the original wiringpi, and it specifically targets the Odroid C1:
git clone https://github.com/hardkernel/wiringPi
So, getting back to the example program build:
- cd RF24/examples_linux
The Makefile will build all of the examples. I have some as-yet-unidentified trouble in the gettingstarted executable, so I had the most success with the pingpair_dyn example program. I started it thusly:
First, make sure the kernel modules are loaded:
- sudo modprobe spicc
- sudo modprobe spidev
Check to see that the /dev/spi* devices exist, and if they do, execute the example program:
Note that the modules could be added to the /etc/modules file to automate this process.
Once running, the program asked whether or not I wanted my first node to “transmit” a ping, or to wait to “receive” a ping (0 or 1 response). I set the first node (the original Homemade Tablet) to be a ping receiver. Then, on the second node (the Yellow Box server), I executed pingpair_dyn, and set it to be a “transmit node”. The resulting outputs are shown at the top of this page (figure 1) and below:
Note that there are some packet drops. This communications setup must factor that into any project scheme. As the distance between the two devices increases, the number of timeouts also increases.
I should add that I needed to modify the hardware setup, before any of this would work. I made the hardware change, not because of anything related to the RF24 stuff, but because the setup for SPI on the Lbuntu Odroid image (at least the one used) – was said to be missing a pull-down. The pulldown can be implemented in software (the driver), or in hardware. So, a quick fix for the missing driver pulldown is a hardware pulldown. In reality, both are hardware pulldowns, it’s just that the pulldown resistor that could be used by the driver is inside of the chip. Anyway:
I put a 4.7 kohm resistor from physical pin 19 to ground, and another 4.7 kohm resistor from physical pin 23 to ground. I got this ingenious idea from Kinsa on the Odroid forum:
It is the third message in the thread. Actually, he uses a 10 kohm resistor, but I have *way* more 4.7 kohm resistors in my junk drawer. One time I ordered 500 resistors as part of a multi-pack, that was supposed to have a few dozen of each of many different resistor values. Instead, I received 500 4.7 kohm resistors. Now, I use 4.7 kohm resistors for EVERYTHING! In reality, the current draw difference is not very much (this is a hobbyist’s opinion, which you may fully disregard – see disclaimer! It seems to work for me.
BTW: the choosing of a value for the pull-up resistors involves a lot more than people generally give a thought to consider. A good rule-of-thumb value is a subject of debate. It depends on a few things including the freqency of operation. I’m not advocating for any particular value. For more of my (non-expert) doings in this area, see:
Figure 3 should be good for keeping some hair on one’s head. I’ve seen so many posts about the nRF24, and how people “can’t get it to work.” When you run any of the example programs, the status byte will be shown. In Figure 3, its value is shown as 0x0e. If this shows up as 0x00 – then you don’t have an SPI connection to the transceiver, let alone an RF connection to any other nodes. It’s necessary to SPI to the hardware before any RF communications will take place!
The range of my setup is less than 20 feet between nodes. I want the low power, because it’ll be a battery setup (solar charged batteries) – and I don’t have the amps to spare. My intended purpose requires (sometimes only 20 feet or less) – but perhaps occasionally about 50 feet. In my case, obstructions (such as walls and appliances) complicate things due to the frequencies that are used, and the absorption inherent therein. So, I’ve contemplated adding a dipole to the transceiver. As an amateur, I’ve done that quite often (but on HF frequencies :-))! I’m still mulling it over, but for a quick info hit on what it’d look like, take a peek at:
I kinda like his little T-Hat transceivers – they’re cute. A dipole IS more directional though, so may not suit all circumstances.
For those interested, this 2.4 GHz transceiver project allies to some extent with some of my other projects at:
Note: the author does not have a recent, applicable background in circuit building, or battery related issues, so this is presented as the work of a hobbyist, and is not meant for duplication by others. Readers should look elsewhere for design advice and info.
Note: The Odroid site is http://www.hardkernel.com and is not affiliated with this site in any way. The nrf24 is a product of https://www.nordicsemi.com – and they are not affiliated with this author or website in any way.