nopnop2002 / esp-idf-mirf

nRF24L01 Driver for esp-idf
MIT License
59 stars 10 forks source link

Slow transmission #5

Closed simeondmr closed 7 months ago

simeondmr commented 2 years ago

Hello,

I'm using the RF24 with esp32-pico mini and esp32-S3. During the data transmit I have noticed that the transmission is slow, despite I have set the speed data rates at 2Mbps(the payload size is 32 bytes).

Transmitter

Nrf24_SetSpeedDataRates(&dev, 1);
for (int i = 0; i < 1000;i++) {
    Nrf24_send(&dev, &data);
    if (!Nrf24_isSend(&dev)) {
        ESP_LOGE(pcTaskGetTaskName(0), "Error sending packet n° %d", i);
    }
    vTaskDelay(1/portTICK_PERIOD_MS);
}

Receiver

Nrf24_SetSpeedDataRates(&dev, 1);
while(1) {
  if (Nrf24_dataReady(&dev)) {
      Nrf24_getData(&dev, data);
  }
  ...
}

What could be the problem? My target is to be able to send at least 64 KByte per second.

Thanks

Simeon

nopnop2002 commented 2 years ago

This repository does not yet support ESP32S3. I haven't got the ESP32S3 yet. II will support it when i get ESP3S3.

simeondmr commented 2 years ago

Ok, thanks. Now I'm using two ESP32 pico mini, but I have the same problem. It took about 9 seconds to send 32000 bytes, that is a lot of time for the 2Mbps config.

could you help me?

nopnop2002 commented 2 years ago

I'll test on my environment.

nopnop2002 commented 2 years ago

I used the Atmega328 to measure the benchmark. For Atmega328 running at 16MHz, the maximum SPI Frequency is 8MHz.

Atmega328--(8MHz)->nRF24L01--(2Mbps)-->nRF24L01--(8MHz)-->Atmega328

Total Bytes=32000 Elasped=5121 MillSecs

32000[Bytes]/5.121[Sec]=6248[Bytes/Sec]=62480[bits/Sec]=62.4K[bps]

This is the effective speed of nRF24L01 for 2Mbps config. 2Mbps is the aerial data rate, not the effective rate.


My library uses SPI speed of 4Mhz. https://github.com/nopnop2002/esp-idf-mirf/blob/master/components/mirf/mirf.c#L23

ESP32--(4MHz)->nRF24L01--(2Mbps)-->nRF24L01--(4MHz)-->ESP32

This is half the Atmega328. Therefore, it takes about 10 seconds. If you change this, it may improve a little. I tried 8Mhz SPI speed but it didn't work properly. If you shorten the length of the SPI jumper wire, it may work even at 10MHz.

nopnop2002 commented 2 years ago

nRF24L01 has "Enhanced ShockBurst" features.

Enhanced ShockBurst automatically sets the PTX(=Transmitter) in receive mode to wait for the ACK packet from PRX(=Receiver). This is the cause of the slowness. Disabling "Enhanced Shock Burst" will speed things up, but will not detect transmission failures.

ESP32 nRF24L01[PTX] nRF24L01[PRX] ESP32
ESP32 --> nRF24L01
nRF24L01 --(Payload)--> nRF24L01
nRF24L01 <--(Ack Packet)-- nRF24L01
nRF24L01 --> ESP32

From datasheet of nRF24L01Plus.


7 Enhanced ShockBurst™ Enhanced ShockBurst™ is a packet based data link layer that features automatic packet assembly and timing, automatic acknowledgement and retransmissions of packets. Enhanced ShockBurst™ enables the implementation of ultra low power and high performance communication with low cost host microcon- trollers. The Enhanced ShockBurst™ features enable significant improvements of power efficiency for bi- directional and uni-directional systems, without adding complexity on the host controller side.

7.1 Features The main features of Enhanced ShockBurst™ are:

•    1 to 32 bytes dynamic payload length
•    Automatic packet handling
•    Automatic packet transaction handling
         X Auto Acknowledgement with payload

         X Auto retransmit

•    6 data pipe MultiCeiver™ for 1:6 star networks

7.2 Enhanced ShockBurst™ overview Enhanced ShockBurst™ uses ShockBurst™ for automatic packet handling and timing. During transmit, ShockBurst™ assembles the packet and clocks the bits in the data packet for transmission. During receive, ShockBurst™ constantly searches for a valid address in the demodulated signal. When Shock- Burst™ finds a valid address, it processes the rest of the packet and validates it by CRC. If the packet is valid the payload is moved into a vacant slot in the RX FIFOs. All high speed bit handling and timing is con- trolled by ShockBurst™.

Enhanced ShockBurst™ features automatic packet transaction handling for the easy implementation of a reliable bi-directional data link. An Enhanced ShockBurst™ packet transaction is a packet exchange between two transceivers, with one transceiver acting as the Primary Receiver (PRX) and the other trans- ceiver acting as the Primary Transmitter (PTX). An Enhanced ShockBurst™ packet transaction is always initiated by a packet transmission from the PTX, the transaction is complete when the PTX has received an acknowledgment packet (ACK packet) from the PRX. The PRX can attach user data to the ACK packet enabling a bi-directional data link.

The automatic packet transaction handling works as follows:

1.     You begin the transaction by transmitting a data packet from the PTX to the PRX. Enhanced
       ShockBurst™ automatically sets the PTX in receive mode to wait for the ACK packet.
2.     If the packet is received by the PRX, Enhanced ShockBurst™ automatically assembles and
       transmits an acknowledgment packet (ACK packet) to the PTX before returning to receive mode.
3.     If the PTX does not receive the ACK packet immediately, Enhanced ShockBurst™ automatically
       retransmits the original data packet after a programmable delay and sets the PTX in receive
       mode to wait for the ACK packet.

In Enhanced ShockBurst™ it is possible to configure parameters such as the maximum number of retrans- mits and the delay from one transmission to the next retransmission. All automatic handling is done without the involvement of the MCU.

simeondmr commented 2 years ago

Hello, first of all, thanks for your answer. I tried 8Mhz SPI speed but it didn't work properly.

ShockBurst According to datasheet: "Set the register EN_AA = 0 and ARC = 0 to disable Enhanced ShockBurst", so I wrote this function that implement it.

void disable_shockburst(NRF24_t * dev)
{
    Nrf24_writeRegister(dev, EN_AA, 0x00, 1);
    Nrf24_writeRegister(dev, ARC, 0x00, 1);
}

Also with ShockBurst disabled I have the same speed.

do you have any other ideas?

Thanks!

lorenzopeluso commented 2 years ago

Hi all.

I've the same problem.

Looking forward to hearing for hits.

Thanks a lot. Lorenzo.

nopnop2002 commented 2 years ago

I tried 8Mhz SPI speed but it didn't work properly.

It works with a short jumper cable.

nopnop2002 commented 2 years ago
void disable_shockburst(NRF24_t * dev)
{
    Nrf24_writeRegister(dev, EN_AA, 0x00, 1);
    Nrf24_writeRegister(dev, ARC, 0x00, 1);
}

ARC is a mask, not a register address. Did you disable EN_AA for both sending and receiving?

simeondmr commented 2 years ago

Yes, I have disabled EN_AA for both. Now I'm trying shorter jumper cable.

nopnop2002 commented 2 years ago

It's ok 10MHz with short cable.

SPI_10MHz-2

nopnop2002 commented 2 years ago

12Mhz is the limit, 14Mhz is unstable.

I think it will be about 3 times faster with 12Mhz.

SPI_12MHz-2 SPI-14Mhz

nopnop2002 commented 2 years ago

I found th reason.

The ESP-IDF SPI driver spi_device_transmit needs 1 tick per transmission.

spi_device_transmit
Send a SPI transaction, wait for it to complete, and return the result
Nrf24_SetSpeedDataRates(&dev, 1);
for (int i = 0; i < 1000;i++) {
    Nrf24_send(&dev, &data);
    if (!Nrf24_isSend(&dev)) {
        ESP_LOGE(pcTaskGetTaskName(0), "Error sending packet n° %d", i);
    }
    vTaskDelay(1/portTICK_PERIOD_MS);
}

1000 ticks are required for 1000 transmissions.

This has nothing to do with SPI bus speed.
The throughput of nRF24L01 is 3,200 bytes / sec. The data rate of nRF24L01 affects the radio range, but not the speed.

Throughput depends on maximum payload size of PHY, not bus speed.

nopnop2002 commented 2 years ago

If you want more fast, use this.

https://github.com/nopnop2002/esp-idf-sx127x

simeondmr commented 2 years ago

OK, tomorrow I will try the lora! Have a good day!

nopnop2002 commented 2 years ago

@simeondmr

I have to apologize to you.

Lora is not fast.

Because Lora is complicated and requires many SPI transactions.

14 ticks are required to send 255 bytes.

This is slower than nRF24L01

simeondmr commented 2 years ago

Ok thanks, my target is to use the nRF24L01 at 64 KByte per seconds because I have to send a lot of audio packets. Also with shorter jumper cable nothing changed. At the moment I have done a PCB and as soon as I get it I will try it.

nopnop2002 commented 2 years ago

2000 transmissions are required to achieve 64K bytes per second. Unfortunately, I have no idea.

simeondmr commented 2 years ago

ok thanks, have a good day

nopnop2002 commented 2 years ago

I used this library and tested it.

https://github.com/nopnop2002/Arduino-STM32-nRF24L01

The above is the same except for this library and SPI-Driver.

Both have the same SPI bus speed. The transmission speed depends on the implementation of the SPI driver. In both cases, the SPI driver is included in the core library.

I think It’s hard 64 KByte per seconds using esp-idf.


Description of data sheet of nRF24L01

  •   Host Interface
         4-pin hardware SPI
         Max 10Mbps
         3 separate 32 bytes TX and RX FIFOs
         5V tolerant inputs
nicogutz commented 10 months ago

This might sound dumb but did you have any serial output on the ESP32 while doing that test @nopnop2002? There is a very big overhead to using printf on the ESP32, LOG macros also use printf. Try the same test without any sort of logging or printing while sending the data.

As far as I can tell, the SPI implementation on the ESP is running on a separate task, so printing will take CPU time away from it or the main process.

nopnop2002 commented 10 months ago

@nicogutz

As you said, SPI driver is running as a background task.

spi_device_transmit is executed by the SPI driver and consumes 1tick of CPU time.

When DMA is enabled, SPI max_transfer_sz defaults to 4092(4K).

This indicates that 4092 bytes of data can be sent in 1 tick.

Therefore, the SPI transmission potential of ESP-IDF is 400Kbytes/Sec.

Unfortunately, nRF24L01's maximum payload size is 32 bytes.

The throughput of nRF24L01 is 3,200 bytes/sec.


The weakness of SPI in a FreeRTOS environment is that it consumes at least one tick, regardless of the data size being transferred.

Whether the transfer data size is 1 byte or 4092 bytes, 1 tick (=10ms) is consumed.

In environments other than FreeRTOS, CPU time is consumed depending on the size of data being transferred.

This has a significant impact on the nRF24L01, which has a small maximum payload size.

If 32-byte SPI transfer is repeated 1000 times, the result will be as follows.