This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

ESB on nRF52 SDK11: not sending ACK payloads

I'm trying to set up an ESB PRX on an nRF52 that has to communicate with an nRF24L01 chip acting as PTX. Because I want to react to the received data as quickly as possible, I tend to call nrf_esb_flush_tx() before writing a new payload into the TX FIFO via nrf_esb_write_payload().

I noticed that transmission of any ACK payload beyond the first one seem to fail. In nrf_esb.c, I stumbled on the following piece of code in the on_radio_disabled_rx() handler:

// Pipe stays in ACK with payload until TX fifo is empty
// Do not report TX success on first ack payload or retransmit
if (p_pipe_info->m_ack_payload != 0 && !retransmit_payload)
{
    if(++m_tx_fifo.exit_point >= NRF_ESB_TX_FIFO_SIZE)
    {
        m_tx_fifo.exit_point = 0;
    }

    m_tx_fifo.count--;
    // ACK payloads also require TX_DS
    // (page 40 of the 'nRF24LE1_Product_Specification_rev1_6.pdf').
    m_interrupt_flags |= NRF_ESB_INT_TX_SUCCESS_MSK;
}

This code seems to be at least part of the cause for my problem. I don't really understand what is supposed to happen here. The m_ack_payload flag is set when there is at least one entry in the m_tx_fifo (immediately after the above snippet). The flag seems to only be reset if either on_radio_disabled_rx() is called while the TX FIFO is empty or if the ESB driver is initialized or disabled. This leads to the above code being executed when receiving the second ESB packet. Because in the meantime, the FIFO has been flushed, incrementing the FIFO exit point will make the current TX payload be an invalid payload.

According to the referenced page 40 in nRF24LE1_Product_Specification_rev1_6.pdf, the TX_DS event is only relevant for a PTX after receiving an ACK payload. Since on_radio_disabled_rx() is called on the PRX side, I don't see, why a TX success event has to be generated here.

In my opinion, a cleaner solution would be to always increment the FIFO exit point after the FIFOs contents have been copied to the current TX payload buffer in on_radio_disabled_rx().

I'm sure there is a good reason for the above code to exist, so I'd be happy if someone could clarify why this is needed and what would go wrong if I removed it and instead called tx_fifo_remove_last() after copying the current FIFO exit point data to the actual TX buffer.

Parents
  • Just experienced this myself today. Looks like the ESB library has a bug.

    Here's how I solved the issue: I changed the following code (starting line 773 nrf_esb.c in SDK 14.1.0):

            case NRF_ESB_PROTOCOL_ESB_DPL:
                {
                    if (m_tx_fifo.count > 0 &&
                        (m_tx_fifo.p_payload[m_tx_fifo.exit_point]->pipe == NRF_RADIO->RXMATCH)
                       )
                    {
                        // Pipe stays in ACK with payload until TX FIFO is empty
                        // Do not report TX success on first ack payload or retransmit
                        if (p_pipe_info->ack_payload == true && !retransmit_payload)
                        {
                            if (++m_tx_fifo.exit_point >= NRF_ESB_TX_FIFO_SIZE)
                            {
                                m_tx_fifo.exit_point = 0;
                            }
    
                            m_tx_fifo.count--;
    
                            // ACK payloads also require TX_DS
                            // (page 40 of the 'nRF24LE1_Product_Specification_rev1_6.pdf').
                            m_interrupt_flags |= NRF_ESB_INT_TX_SUCCESS_MSK;
                        }
    
                        p_pipe_info->ack_payload = true;
    
                        mp_current_payload = m_tx_fifo.p_payload[m_tx_fifo.exit_point];
    
                        update_rf_payload_format(mp_current_payload->length);
                        m_tx_payload_buffer[0] = mp_current_payload->length;
                        memcpy(&m_tx_payload_buffer[2],
                               mp_current_payload->data,
                               mp_current_payload->length);
                    }
                    else
                    {
                        p_pipe_info->ack_payload = false;
                        update_rf_payload_format(0);
                        m_tx_payload_buffer[0] = 0;
                    }
    
                    m_tx_payload_buffer[1] = m_rx_payload_buffer[1];
                }
                break;
    

    to the following:

            case NRF_ESB_PROTOCOL_ESB_DPL:
                {
                	// Pipe stays in ACK with payload until TX FIFO is empty
    				// Do not report TX success on first ack payload or retransmit
    				if (p_pipe_info->ack_payload == true && !retransmit_payload)
    				{
    					if (++m_tx_fifo.exit_point >= NRF_ESB_TX_FIFO_SIZE)
    					{
    						m_tx_fifo.exit_point = 0;
    					}
    
    					m_tx_fifo.count--;
    
    					// ACK payloads also require TX_DS
    					// (page 40 of the 'nRF24LE1_Product_Specification_rev1_6.pdf').
    					m_interrupt_flags |= NRF_ESB_INT_TX_SUCCESS_MSK;
    				}
    
                    if (m_tx_fifo.count > 0 &&
                        (m_tx_fifo.p_payload[m_tx_fifo.exit_point]->pipe == NRF_RADIO->RXMATCH)
                       )
                    {
                        p_pipe_info->ack_payload = true;
    
                        mp_current_payload = m_tx_fifo.p_payload[m_tx_fifo.exit_point];
    
                        update_rf_payload_format(mp_current_payload->length);
                        m_tx_payload_buffer[0] = mp_current_payload->length;
                        memcpy(&m_tx_payload_buffer[2],
                               mp_current_payload->data,
                               mp_current_payload->length);
                    }
                    else
                    {
                        p_pipe_info->ack_payload = false;
                        update_rf_payload_format(0);
                        m_tx_payload_buffer[0] = 0;
                    }
    
                    m_tx_payload_buffer[1] = m_rx_payload_buffer[1];
                }
                break;
    

    This moves the completion code outside of the check for new packets to send. The SDK's code would send uninitialized data from the FIFO, which usually worked, but sometimes failed disastrously.

    It's a pretty serious bug that in practice makes PRX ACK payloads unusable. Hopefully someone from Nordic will see this post and incorporate the fix into the next SDK release.

  • You are absolutely right that this is a bug in the ESB library. Unfortunately, it has not been fixed in the SDK yet, but I will bump this issue internally.

    Your modifications seem valid, and can hopefully be useful for others until the SDK incorporates a fix.

  • Hi,

    I do not have any more information that what is in this thread. The suggested fix by is valid and can be used with later SDKs.

    This has not yet been fixed in the SDK, as it slipped through the system because of a mishap on my part. I have bumped it again so that it can hopefully be fixed in a future release.

  • Any reason why this isn't fixed in SDK 15.3.0 yet?

  • The 15.3 release of the nRF5 SDK was limited in scope, so unfortunately this is among the several things that was not prioritized.

Reply Children
No Data
Related