Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ultra slow speeds #24

Closed
Martincic opened this issue Feb 7, 2021 · 3 comments
Closed

Ultra slow speeds #24

Martincic opened this issue Feb 7, 2021 · 3 comments

Comments

@Martincic
Copy link

Martincic commented Feb 7, 2021

Problem

I am aware of nrf240L1+ module is capable of 2mb/s speeds and I pretty sure both of my raspberry pi's on each end can handle them, but the actual transfer time is 40 minutes to send a 2.6Mb file. Could this be faster in some way, what am I missing?

How

I'm trying to stream an image from one NRF240L+ module to another and the current setup is only a couple of meters apart pointing directly at each other. I am using your example (nrf24l01_stream_test) which I've modified in the following manner:

  • make_buffers() method is opening jpeg file, reading it as hex, constructing buffers with 32byte chunks, and returning buffers
  • master remains untouched and sends these buffers to the slave
  • slave() instantiates byte array which appends all received bytes and finally writes this to "image.png" file

This is working with some data loss and image disruption which is precisely what I need. I tried manually setting the speed to 2Mb/s and turning off auto_ack but it had no noticeable effect.

Transmission log

  • 13.53 - start transmission
  • 14.03 -ongoing 0.9Mb sent
  • 14.28 - ongoing 2.1Mb sent
  • 14:35 - ongoing 2.5Mb sent
  • 14:45 - end transmission 2.6Mb sent

Code

make_buffers()

def make_buffers(size=32):
    """return a list of payloads"""
    # we'll use `size` for the number of payloads in the list and the
    # payloads' length
    buffers = []
    with open("coal.jpeg", "rb") as image:
      f = image.read()     
      b = bytearray(binascii.hexlify(f))
  
    counter = 0
    while counter < sys.getsizeof(b):
        counter += 32
        if not counter > sys.getsizeof(b):
            buffers.append(b[counter:counter+32])
    return buffers

slave()

def slave(timeout=5):
    """Stops listening after a `timeout` with no response"""
    bytes = b''
    nrf.listen = True  # put radio into RX mode and power up
    count = 0  # keep track of the number of received payloads
    start_timer = time.monotonic()  # start timer
    while time.monotonic() < start_timer + timeout:
        if nrf.available():
            count += 1
            # retreive the received packet's payload
            buffer = nrf.read()  # clears flags & empties RX FIFO
            print("Received: {} - {}".format(buffer, count))
            bytes += buffer
            start_timer = time.monotonic()  # reset timer on every RX payload

    # recommended behavior is to keep in TX mode while idle
    nrf.listen = False  # put the nRF24L01 is in TX mode
    print(bytes[0:64])
    f = open("image.jpeg", 'wb')
    f.write(binascii.unhexlify(bytes))
    f.close()
@2bndy5
Copy link
Member

2bndy5 commented Feb 7, 2021

  1. What version of the library are you using? v2.00 or v1.3.0 had significant speed ups implemented.
  2. master_fifo() had much better performance on a RPi compared to master() in the streaming _test.py
  3. SPI implementation on the RPI is noticeably slow. At this point, I can't think of another way to speed up the library without re-writting adafruit's PureIO libary in C++ (not an easy task).

BTW, data_rate is in bits per second, not bytes per seconds. Turning off auto-ack will most definitely cause data loss, especially for that much data being streamed so quickly.

@2bndy5
Copy link
Member

2bndy5 commented Feb 8, 2021

I can tell by the code you posted, you're using the speed boost included with v2.0.0. I'm sorry, but if you're looking for speed, then python isn't your best friend. Try using TMRh20's RF24 library, which is much faster because its written in C++ (comes also with a python wrapper that is just as fast as C++).

I recently (& coincidentally) made a refactoring change (on my dev branch) that would allow passing in whatever spi/csn/ce_pin objects you want as long as there's a new HWMixin class that can take exactly the objects you passed.

In short, I think this library is starting to outgrow just circuitpython. In the future I may be able to support the popular pigpio, RPi.GPIO + spidev, etc... (not to mention more native support for MicroPython). This also opens up an opportunity to offer NerdRalph's 3 and 4 pin solutions.

@2bndy5
Copy link
Member

2bndy5 commented Feb 15, 2021

update from my dev branch testing: I've been testing the library on RPi2 and RPi4 using spidev (written in C; wrapped into python) instead of Adafruit's busio for SPI implementation. Consequently, I've started using GPIO8 for the CSN pin (on the default SPI bus) because its faster to let the spidev kernel manage that.

These results are from a modified version of master() from stream_test.py. (on 1Mbps data_rate)

Test result sending a large-ish (1.24 MB) file from RPi4 to RPi2:

1307379 bytes split into 40857 payloads
Transmission took 56.005716284999835 s
successfully sent 100.0% (40857/40857) of LogoLarge.xcf

Mirrored test sending the same file to RPi4 from RPi2:

1307379 bytes split into 40857 payloads
Transmission took 55.499714189999395 s
successfully sent 100.0% (40857/40857) of LogoLarge.xcf

I have made a few small code changes that should speed things up, but using spidev seems to be the best speed-up. I doubt it would take more than 5 minutes to transfer a 2.5 MB file now 🎉 (upon next release). Also, I have not verified data is un-corrupted on RX side.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants