[nRF24L01+] How to use Auto Acknowledge

Hello all,

1. I have a transmitter (Arduino Pro Mini 5V) connected to a nRF24L01+. I use the following code to set up the radio.

    radio.begin();
    radio.setChannel(125);
    radio.setPALevel(RF24_PA_LOW);
    radio.setDataRate(RF24_1MBPS);
    radio.setAddressWidth(5);
    radio.setAutoAck(true);
    radio.setRetries(5, 3);
    radio.setPayloadSize(sizeof(radio_data));
    radio.openWritingPipe(address);
    radio.stopListening();

2. I have a receiver (ESP32) coonecter to a nRF24L01+. I use the following code to set up the radio.

    radio.begin();
    radio.setChannel(125);
    radio.setPALevel(RF24_PA_LOW);
    radio.setDataRate(RF24_1MBPS);
    radio.setAddressWidth(5);
    radio.setAutoAck(true);
    radio.setRetries(5, 3);
    radio.setPayloadSize(sizeof(radio_data));
    radio.openReadingPipe(0, address);
    radio.startListening();

3. When I want to transmit data, I call the function write.

The return of the call to the function write is always false, meaning that auto acknowledgement goes wrong.

Have you any idea of what I did wrong ?

Thanks for your help.

Parents
  • Hi 

    Is anything received by the ESP32 board?

    The nRF24L01+ is rated to 3.6V maximum, so I think the first order of business would be to test this on boards that support a lower supply voltage. Correct behavior can not be guaranteed when you're running the nRF device at 5V, and it might damage the module over time. 

    Best regards
    Torbjørn

  • Hello,

    First, the nRF24L01+ is not supplied with the 5V of transmitter Arduino, but with 3.3V.

    Second, with the channel set to 125, the receiver ESP32 is not receiving at all. If I remove the call to setChannel, the ESP32 is receiving around 20% of the frame and in that case, the Arduino is getting the ACK.
    So, 80% of frame are lost with no ACK.

    As an information, there is a 10µF capacitor at the pin GND/3.3V of the receiver nRF24L01+ and a 100µF capacitor for the transmitter nRF24L01+.

    Best regards.

  • Hello,

    I agree with your proposal.

    Let me know the data you want me to send/receive on the SPI as a test sequence and what result to provide to you.

    Best regards,

    Pascal

  • Hi Pascal

    Probably the most stripped down sequence for establishing communication goes something like this:

    PTX

    Set CONFIG register to 0x0E  (PRWUP = 1, CRC 16 bit, PRIM_RX 0)
    Write 0x20, 0x0E

    Add a 2ms delay

    Now the transmitter should be ready. To send a packet, start by uploading a packet
    Write 0xA0, 0x01, 0x02, 0x03, 0x04 (only the first byte is important, the remaining bytes can be whatever you like)

    Pulse the CE line for 100us in order to start the transmission

    In a loop, read the STATUS register and wait for bit 4 or 5 to be set
    Write 0x07, 0x00 and check the return value. If nothing happened the return value should be 0x0E. Once you get an interrupt it should be 0x2E (TX successful) or 0x1E (TX failed). 

    To prepare for another packet, clear the IRQ bits by writing 0x70 to the STATUS register:
    Write 0x27, 0x70

    PRX

    Set CONFIG register to 0x0F  (PRWUP = 1, CRC 16 bit, PRIM_RX 1)
    Write 0x20, 0x0F

    Add a 2ms delay

    Configure the payload length on pipe 0 to 4 bytes (or whichever number of bytes you plan to send from the PTX side)
    Write 0x31, 0x04

    Set the CE line high permanently to enable the receiver

    In a loop, read the STATUS register and wait for bit  6 to be set
    Write 0x07, 0x00 and check the return value. If nothing happened the return value should be 0x0E. Once you receive a packet it should be 0x40.

    To prepare for another packet, clear the IRQ bits by writing 0x70 to the STATUS register:
    Write 0x27, 0x70

    Would you be able to follow this procedure and see if the status register changes on either side, indicating a successful transaction? 

    There is a bit more work if you want ot read out the payload on the RX side, but the main point at the moment is to verify that your hardware works properly. 

    Best regards
    Torbjørn

  • Hello,

    I wrote the code based on the above sequence for the PRX and PTX. I only add the reading of the received frame in the PRX sequence.

    It works fine.

    The PTX sends the frame every 500ms and then the PRX receives it perfectly at the same rate.

    Do you want to get SPI captures, from PRX, from PTX?

    What are the next steps?

    Best regards,

    Pascal

  • Hello,

    Today, I got some errors during the auto ACK.

    I share with you the capture file with CE from the start : https://drive.google.com/file/d/1qYhx9URnSculNCKtLedLqEY8i-KrhAHp/view?usp=sharing

    Best regards,

    Pascal

  • Hello,

    I share with you a capture file with CEs of SPI for both PTX and PRX from the start : https://drive.google.com/file/d/1mi6D-tu33AO6Ovo6XV2cg7CNmShpeRCI/view?usp=sharing

    At 16s141ms800, there is a fail of the auto ACK (last status equals to 0x1E).
    Just before, at 16s141ms100, this is the TX data packet corresponding to the fail auto ACK. The last byte of this data is 0x19 and can be used to search in the PRX capture if the corresponding data has been received.
    The last byte of the TX data packet is increased by 1 at each transfer, so that this last byte is different from one transfer to the previous/next one.
    If you scrolls down to look at the RX SPI capture, you can see that the data packet with last byte equals to 0x19 is read from the nRF24L01 just before 16s141ms800.

    Additional question: do you know why at 4s612ms440 there is a status set to 0x0C on the RX MISO, which does not seem to correspond to something correct?

    Best regards,

    Pascal

Reply
  • Hello,

    I share with you a capture file with CEs of SPI for both PTX and PRX from the start : https://drive.google.com/file/d/1mi6D-tu33AO6Ovo6XV2cg7CNmShpeRCI/view?usp=sharing

    At 16s141ms800, there is a fail of the auto ACK (last status equals to 0x1E).
    Just before, at 16s141ms100, this is the TX data packet corresponding to the fail auto ACK. The last byte of this data is 0x19 and can be used to search in the PRX capture if the corresponding data has been received.
    The last byte of the TX data packet is increased by 1 at each transfer, so that this last byte is different from one transfer to the previous/next one.
    If you scrolls down to look at the RX SPI capture, you can see that the data packet with last byte equals to 0x19 is read from the nRF24L01 just before 16s141ms800.

    Additional question: do you know why at 4s612ms440 there is a status set to 0x0C on the RX MISO, which does not seem to correspond to something correct?

    Best regards,

    Pascal

Children
  • Hi Pascal

    I am now back from vacation and I can take a look at the traces. Could you just let me know if there has been any updates or discoveries from you in the mean time, or if the question is still the same as when you posted your question? 

    Best regards
    Torbjørn

  • Hello,

    My concern is still valid.

    Have a look to my last 3 messages above.

    The last message above includes a link to a capture of both SPIs of PTX and PRX.

    Best regards,

    Pascal

  • Hi Pascal

    _pascalh said:
    If you scrolls down to look at the RX SPI capture, you can see that the data packet with last byte equals to 0x19 is read from the nRF24L01 just before 16s141ms800.

    If I understand your question correctly you are wondering why the PTX is getting the MAX_RT (TX failed) interrupt even when the packet is received by the PRX?

    This can happen whenever the original packet from the PTX to the PRX is received by the PRX, but the ACK packet back to the PTX is lost. In this case the PRX will report an RX interrupt and the PTX will report the MAX_RT interrupt. The normal way to handle this is to retransmit the packet from the PTX, then the PRX will read it as a retransmission and simply ACK the packet again without adding it to the RX FIFO (or raising the RX interrupt again). 

    Figure 24 on page 48 of the datasheet shows a variant of this scenario, where neither of the ACK packets sent by the PRX are received by the PTX, and the PTX will report the MAX_RT interrupt even if the packet was received by the PRX. 

    Increasing the retransmit counter (ARC) in the SETUP_RETR register will reduce the chance of this happening, since the PTX will attempt more times before issuing the MAX_RT interrupt.

    Looking at your trace it doesn't seem like this register is set to a higher value. 

    _pascalh said:
    Additional question: do you know why at 4s612ms440 there is a status set to 0x0C on the RX MISO, which does not seem to correspond to something correct?

    Interesting, I have never seen this behavior before. It seems the STATUS register is being read just as a packet is received, and an intermediary value between 0x0E and 0x40 is returned. This might be a side effect of reading the STATUS register at such a high rate (when using the IRQ line you typically only read the STATUS register once IRQ goes low). 

    Either way it seems the library is using the second byte on MISO to determine status, so this shouldn't have a negative effect on the application.  

    Best regards
    Torbjørn

  • Hello,

    I modify the PTX software as follow:

     - set SETUP_RETR to 0x1A

    I modify the PRX software as follow:

     - use the IRQ instead of polling the status register to know if there is data in the RX FIFO

    I captured both SPI for PRX and PTX from the start:

    https://drive.google.com/file/d/1y1i61q-qweEQPORg_KDgUk9I_-D6kJQd/view?usp=drive_link

    Every thing seems to be ok.

    Let me know your analysis.

    Best regards,

    Pascal

  • Hi

    Using the IRQ line is a good idea, then you don't have to waste time and power checking the status register continuously. 

    If possible I would recommend doing it on the PTX side also. 

    One thing I noticed is that you don't check the status register or the length of the RX payload after the IRQ line goes low, before you read out the payload. This should work fine if you will only ever use a static payload length, but if you ever want to be able to send packets with a dynamic payload length then you need to add some code on the PRX side to check the length of the payload before you read it out. 

    Best regards
    Torbjørn

Related