nRF24 / CircuitPython_nRF24L01

CircuitPython driver library for the nRF24L01 transceiver.
http://circuitpython-nrf24l01.rtfd.io/
MIT License
45 stars 11 forks source link

Support for Adafruit FT232H Breakout #39

Closed De-Man closed 2 years ago

De-Man commented 2 years ago

Hi Team, first of all thank you for your work on this.

I am wanting to use a Adafruit FT232H breakout via its SPI to communicate to an Arduino that is using the RF24 library.

FT232 inherently uses circuit python.

I couldn't $pip3 install circuitpython-nrf24l01 as I am running the FT232 from MacOS, and CircuitPython_nRF24L01 has SpiDev dependancy. So I just downloaded the repo and added into the project. I am also using Adafruit's busio instead os SpiDev for the SPI bus.

Using your 'simple example' as an example all I have really done is added the following code:

"""
Simple example of using the RF24 class.
"""
import time
import busio
import struct
import board # <<-- HERE
from digitalio import DigitalInOut

# if running this on a ATSAMD21 M0 based board
# from circuitpython_nrf24l01.rf24_lite import RF24
from circuitpython_nrf24l01.rf24 import RF24

# invalid default values for scoping
SPI_BUS, CSN_PIN, CE_PIN = (None, None, None)

try:  # on Linux
    import spidev

    SPI_BUS = spidev.SpiDev()  # for a faster interface on linux
    CSN_PIN = 0  # use CE0 on default bus (even faster than using any pin)
    CE_PIN = DigitalInOut(board.D22)  # using pin gpio22 (BCM numbering)

except ImportError:  # on CircuitPython only
    # # using board.SPI() automatically selects the MCU's
    # # available SPI pins, board.SCK, board.MOSI, board.MISO
    # SPI_BUS = board.SPI()  # init spi bus object

    # # change these (digital output) pins accordingly
    # CE_PIN = DigitalInOut(board.D4)
    # CSN_PIN = DigitalInOut(board.D5)

    # For Mac:
    # Init FTDI 
    spi = busio.SPI(board.SCK, board.MOSI, board.MISO)  # <<-- HERE
    # change these (digital output) pins accordingly
    CE_PIN = DigitalInOut(board.D7)                     # <<-- HERE
    CSN_PIN = DigitalInOut(board.D6)                  # <<-- HERE

# initialize the nRF24L01 on the spi bus object
...

This is 25% working, I am able to transmit data from the Mac to the Arduino. With the caveat of: I still get the "send() failed or timed out" from my Mac meaning .send is returning a False. I am unable to transmit data from the Arduino to the Mac.

the nRF sensors are all wired up correctly and work as I have tested them TxRx both ways using 2 off Arduinos. I am pretty sure the fault lies with my poor porting of your library to MacOS + FDTI.

Hopefully you may be able to look at this and easily implement a solution so I can use the FDTI interface.

Thank you in Advanced.

2bndy5 commented 2 years ago

I dreamt about this type of support a while back, but I did not end up getting one of those FTDI boards. I have not thought about it since... Can you supply links to docs about using this board (it would save me some time)?

CircuitPython_nRF24L01 has SpiDev dependancy

It does, but it shouldn't be needed to install on anything but Linux. I specifically put that condition in the requirements.txt: https://github.com/nRF24/CircuitPython_nRF24L01/blob/c800869415275f960f97605c28529f9fa5e679b9/requirements.txt#L3

but maybe I can improve the setup.py in this regard:

https://github.com/nRF24/CircuitPython_nRF24L01/blob/c800869415275f960f97605c28529f9fa5e679b9/setup.py#L15-L16 I wouldn't be too surprised if running

python -c "import os; print(os.name)"

displays "posix" on mac (I'm rather biased against macs - sorry).


So, Using borad.SPI() should be equivalent as

spi = busio.SPI(board.SCK, board.MOSI, board.MISO)

Maybe specifying the SPI bus' pins is required for using this FTDI lib/board from a PC?

However, I'm surprised if this change worked at all since it sets a var named spi while the example code uses

nrf = RF24(SPI_BUS, CSN_PIN, CE_PIN)

"send() failed or timed out" from my Mac meaning .send is returning a False

This is usually indicative of a power supply problem. Just because you verified the radio's worked on a different power supply doesn't mean the radios will work on all power supplies. I also have to ask: What exact version of nRF24L01 are you using (store link please)? I'm also curious if you read #19.

De-Man commented 2 years ago

Hi bndy5, yes, I have read #19, Yes potentially a power supply issue, I'll check.

As for your other questions:

"""
Simple example of using the RF24 class.
"""
import time
import busio
import struct
import board # <<-- HERE
from digitalio import DigitalInOut

# if running this on a ATSAMD21 M0 based board
# from circuitpython_nrf24l01.rf24_lite import RF24
from circuitpython_nrf24l01.rf24 import RF24

# invalid default values for scoping
SPI_BUS, CSN_PIN, CE_PIN = (None, None, None)

try:  # on Linux
    import spidev

    SPI_BUS = spidev.SpiDev()  # for a faster interface on linux
    CSN_PIN = 0  # use CE0 on default bus (even faster than using any pin)
    CE_PIN = DigitalInOut(board.D22)  # using pin gpio22 (BCM numbering)

except ImportError:  # on CircuitPython only
    # # using board.SPI() automatically selects the MCU's
    # # available SPI pins, board.SCK, board.MOSI, board.MISO
    # SPI_BUS = board.SPI()  # init spi bus object
    spi = board.SPI()  # init spi bus object

    # # change these (digital output) pins accordingly
    # CE_PIN = DigitalInOut(board.D4)
    # CSN_PIN = DigitalInOut(board.D5)

    # For Mac:
    # Init FTDI 
    spi = busio.SPI(board.SCK, board.MOSI, board.MISO)  # <<-- HERE
    # change these (digital output) pins accordingly
    CE_PIN = DigitalInOut(board.D7)                     # <<-- HERE
    CSN_PIN = DigitalInOut(board.D6)                       # <<-- HERE

# initialize the nRF24L01 on the spi bus object
# nrf = RF24(SPI_BUS, CSN_PIN, CE_PIN)
nrf = RF24(spi, CSN_PIN, CE_PIN)
# On Linux, csn value is a bit coded
#                 0 = bus 0, CE0  # SPI bus 0 is enabled by default
#                10 = bus 1, CE0  # enable SPI bus 2 prior to running this
#                21 = bus 2, CE1  # enable SPI bus 1 prior to running this

# set the Power Amplifier level to -12 dBm since this test example is
# usually run with nRF24L01 transceivers inT close proximity: "pa_level must be -18, -12, -6, or 0 (in dBm)"
nrf.pa_level = -12

# Address length____________5 bytes
address = [b"00001", b"00002"]
...
De-Man commented 2 years ago

and also here up to 500mA, so should be good, but I'll check actual.

2bndy5 commented 2 years ago

Thanks for clarifying the code modifications. I just wanted to be sure since I'm not there by your side.


Correct - posix

Thanks for reporting this. I have adjusted the setup.py file on the no-more-upy branch. Can you test the following to see if it installs on mac?

pip3 install git+https://github.com/nRF24/CircuitPython_nRF24L01.git@no-more-upy

Sorry if this is too demanding, but you're the only person I know with a mac - your feedback is valuable to me here.


and also here up to 500mA, so should be good, but I'll check actual.

I saw that also on the store page, but my experience leads me to think that a good portion of that may be consumed by the FTDI chip itself (or maybe other peripheral connections).

I assume this means that you're using the newer version of that FTDI board (which was revised in 2020).


BTW, I meant "what hardware version of the radio are you using?" Is it from ebyte? Is it a generic pack from amazon? Is it from Sparkfun? If you could supply the store link from where you purchased the radio, I'd be better equipped to understand your scenario.

Also, are you using any capacitors? What about a PCB or adapter board that goes in between the radio and the FTDI board?

2bndy5 commented 2 years ago

ok, I read through that tutorial you linked to...

Setting aside the lib install on mac problem, I don't see anything that might need to be done on our end (in terms of hardware support). I think all you needed to actually do is modify the CE & CSN pin numbers in the examples. The example snippets for SPI devices in that tutorial use both board.SPI() and busio.SPI(board.SCK, board.MOSI, board.MISO) to instantiate the SPI bus - not surprising because they are equivalent under the hood.

This makes me think that it is definitely a power stability problem.

2bndy5 commented 2 years ago
address = [b"00001", b"00002"]

This is bad addressing. Anything with consecutive uniformed bit patterns (longer than 2 bits) is going to have significant signal loss because the radio's firmware has trouble decoding the address from other data in the packet. Also the unique byte in the address should be at the beginning due to how bytes objects are stored in memory.

>>> from circuitpython_nrf24l01.rf24 import address_repr
>>> address_repr(b'00001', delimit=" ")
'31 30 30 30 30'
>>> [bin(int(byte, 16)) for byte in address_repr(b'00001', delimit=" ").split()]
['0b110001', '0b110000', '0b110000', '0b110000', '0b110000']
De-Man commented 2 years ago

Hi 2bndy5

Thanks for reporting this. I have adjusted the setup.py file on the no-more-upy branch. Can you test the following to see if it installs on Mac?

Confirmed, This 'pip install' is now working thank you!

Sorry if this is too demanding, but you're the only person I know with a mac - your feedback is valuable to me here.

You're the one helping me, so no apology required, thank you for your support.

I assume this means that you're using the newer version of that FTDI board (which was revised in 2020).

Correct, using the newest version with USB-C port.

BTW, I meant "what hardware version of the radio are you using?" Is it from ebyte? Is it a generic pack from amazon? Is it from Sparkfun? If you could supply the store link from where you purchased the radio, I'd be better equipped to understand your scenario.

From here, let me know if this detail suffices?

Also, are you using any capacitors? What about a PCB or adapter board that goes in between the radio and the FTDI board?

This is bad addressing. Anything with consecutive uniformed bit patterns (longer than 2 bits) is going to have significant signal loss because the radio's firmware has trouble decoding the address from other data in the packet. Also the unique byte in the address should be at the beginning due to how bytes objects are stored in memory.

Can you please recommend how I should be addressing then.

As for the power issue, I need to pull my Oscope from out of the roof and I'll get a better representation of everything.

However, from a multimeter, between vcc and gnd of the nRF24: For the Arduinos: Rx Mode = ~ 20 mA Tx Mode = ~8 mA

FDTI = Rx Mode = ~ 23 mA Tx Mode = ~8 mA

Recapping Arduino - Arduino = OK Arduino - FTDI = Only able to receive from the Arduino side. No feedback at all on the FTDI side.

2bndy5 commented 2 years ago

Can you please recommend how I should be addressing then.

Bad addressing can be avoided by heading ManiacBug's advice from here

For now, just stick with what the examples use. This will also provide a baseline for me to compare to.


From here, let me know if this detail suffices?

That info is good enough, thank you. Those PA/LNA modules are a pain when it comes to power usage. An oscilliscope should show the instantaneous peaks in current consumption. You should see these peaks whenever the radio tries to TX (this includes the ACK packets - with or without ACK payloads attached).

We've been using a lowered PA level (a software hack) in the examples to try to avoid the higher power demands of those PA/LNA radios. Lots of people seem to like those things, but I've never had consistently good/reliable experiences with them (as I've documented in the docs' troubleshooting page). Remember: "bigger is not always better".

Have you tried using electromagnetic shielding? The capacitor's value seem ok, but it might be more stable with another smaller (like 10uF) capacitor in parallel with your 100 uF.


When you say "Arduino", are you using CirPy lib or the Arduino RF24 C++ lib? There are a few differences in the lib's default values.

De-Man commented 2 years ago

Just on the bad addressing thing, I think you mean something like this:

# Address length____________5 bytes
address = [b'\x01\00\00\00\00', b'\x02\00\00\00\00']
De-Man commented 2 years ago

That info is good enough, thank you. Those PA/LNA modules are a pain when it comes to power usage. An oscilliscope should show the instantaneous peaks in current consumption. You should see these peaks whenever the radio tries to TX (this includes the ACK packets - with or without ACK payloads attached).

Roger that, I'll get the Oscope out tomorrow.

And, I'll look at the other references you have provided me. Thank you for you instantaneous support.

De-Man commented 2 years ago

I'm using the R24 C++ lib for the Arduino

2bndy5 commented 2 years ago

Just on the bad addressing thing, I think you mean something like this:

# Address length____________5 bytes
address = [b'\x01\00\00\00\00', b'\x02\00\00\00\00']

That is worse, so yeah I guess. Any time the LSB contains a series of bits 0101 or 0110 or 0011 or 1010 ... ManiacBug describes it better in that blog I linked.

I'm using the R24 C++ lib for the Arduino

ok then, look in the CirPy example and uncomment the lines about dynamic_payloads and payload_length.

De-Man commented 2 years ago

Hi 2bndy5

Ok so it is now working.

For some clarity on above. When you asked:

When you say "Arduino", are you using CirPy lib or the Arduino RF24 C++ lib? There are a few differences in the lib's default values.

I thought you meant on the Arduino side.

Arduino: I have been using the RF24 C++ lib. MacOS: I have been using your circuit python library. i.e. from circuitpython_nrf24l01.rf24 import RF24 I think this is what you mean by “CirPy” as the Python CIRpy module I don’t see to be relevant.

Here is some general data for your records, please note the mV in the top of the images:

Interesting to note: the FDTI provides greater power than the AMS1117.

The final straw was, and I should have figured this comparing the settings through nrf.print_details() (MacOS side) and radio.printPrettyDetails() (Arduino side) when I was aligning the settings a couple of days ago… human error of over looking things. Your statement of uncommenting dynamic payloads fixed the issue. Aligning these whether dynamic or not, enabled a successful transfer. Here is some transfer rate data.

MacOS (Master) to Arduino (Slave) output snip:

Transmission successful! Time to Transmit: 26633.292 us. Sent: 5.4399999999999284
Transmission successful! Time to Transmit: 23857.125 us. Sent: 5.449999999999928
Transmission successful! Time to Transmit: 23611.584 us. Sent: 5.459999999999928
Transmission successful! Time to Transmit: 31373.375 us. Sent: 5.469999999999928

Arduino (Master) to MacOS (Slave) output snip:

Transmission successful! Time to transmit = 564 us. Sent: 6.69
Transmission successful! Time to transmit = 560 us. Sent: 6.70
Transmission successful! Time to transmit = 564 us. Sent: 6.71
Transmission successful! Time to transmit = 564 us. Sent: 6.72 

Generally, the current output seems to look fine, however, i did purchase a AMS1117 3.3v reg. This is where it first started working after aligning dynamic payloads. However, changing it back to direct FDTI also worked.

Thank you for your help on this. Let me know what your thoughts are.

2bndy5 commented 2 years ago

I think this is what you mean by “CirPy”

Indeed. It is tiresome to keep writing out the word CircuitPython so many times. If I said CPy, then I'd be referring to a native python distribution...

I did not add the 10uF/(less than 10uF), I’ll do that after I’ve done further testing.

Judging by the noise in those scope readings, you should be fine to forego additional caps. Although, more stability is always a welcome thing.

Your statement of uncommenting dynamic payloads fixed the issue

Good to know. In the future I'll have to remember to ask this first when someone says "Arduino". FWIW, that info is available in the docs for this lib's examples (under the section "TMRh20’s C++ libraries")

As you can see, MacOS (slave) is extremely slow, what is your thoughts on this

I was afraid this would happen. Its not your OS. Its barely even a library problem (which is already as optimized as I can make it). CirPy runs annoying slow on bare metal (referring to CirPy capable MCUs). The problem lies with using the FTDI board.

The implementation that CirPy is using to communicate to the FTDI board is dependent on a Serial bus that's enumerated as a USB device. Serial buses are without a doubt the slowest data bus there is (excluding the OneWire protocol). This is why I decided not purchase one of those boards.

If you wanted to control the radio from your computer, then a Serial bus is the easiest solution. However, I would have written an app that runs on bare metal and takes input from USB Serial. That way, the shear amount of data needed to traverse the Serial bus (over USB) could be significantly less. Although, I don't think this idea would too much faster because it still relies on a Serial bus.

2bndy5 commented 2 years ago

I'm closing this because it seems to be solved. You can still share your developments/thoughts here.