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

Implementing ACK in software ESB

Hello,

I have to implement ESB on nRF52 bare metal (using the RADIO peripheral). I can receive packets from the nRF24, but I need to implement the ACK, and I'm not sure what this looks like. From the nrf24l01+ datasheet, I know a packet has a preamble, address, packet control field, payload and CRC.

I know that the radio stores the S0, length, S1 and payload fields in memory. So how would I set these fields for the ACK?

In this case, for ESB, there is no S0, the length is 6 bits, S1 is 3 bits (2 bit PID and 1 bit NOACK). I do not need to send a payload back yet, although I would appreciate an explanation of how the packets would be different in the event that I returned a payload with the ACK.

What should I set these fields to for the ACK? And what about the CRC?

Best

Parents
  • Hi Cwmoreiras,

    just out of curiosity, why can't you use the ESB implementation in our SDK?  It is backwards compatible with the nRF24, see Backward compatibility

    Looking at our ESB implementation I found the following functions

    static void update_rf_payload_format_esb_dpl(uint32_t payload_length)
    {
    #if (NRF_ESB_MAX_PAYLOAD_LENGTH <= 32)
        // Using 6 bits for length
        NRF_RADIO->PCNF0 = (0 << RADIO_PCNF0_S0LEN_Pos) |
                           (6 << RADIO_PCNF0_LFLEN_Pos) |
                           (3 << RADIO_PCNF0_S1LEN_Pos) ;
    #else
        // Using 8 bits for length
        NRF_RADIO->PCNF0 = (0 << RADIO_PCNF0_S0LEN_Pos) |
                           (8 << RADIO_PCNF0_LFLEN_Pos) |
                           (3 << RADIO_PCNF0_S1LEN_Pos) ;
    #endif
        NRF_RADIO->PCNF1 = (RADIO_PCNF1_WHITEEN_Disabled    << RADIO_PCNF1_WHITEEN_Pos) |
                           (RADIO_PCNF1_ENDIAN_Big          << RADIO_PCNF1_ENDIAN_Pos)  |
                           ((m_esb_addr.addr_length - 1)    << RADIO_PCNF1_BALEN_Pos)   |
                           (0                               << RADIO_PCNF1_STATLEN_Pos) |
                           (NRF_ESB_MAX_PAYLOAD_LENGTH      << RADIO_PCNF1_MAXLEN_Pos);
    }
    
    
    static void update_rf_payload_format_esb(uint32_t payload_length)
    {
        NRF_RADIO->PCNF0 = (1 << RADIO_PCNF0_S0LEN_Pos) |
                           (0 << RADIO_PCNF0_LFLEN_Pos) |
                           (1 << RADIO_PCNF0_S1LEN_Pos);
    
        NRF_RADIO->PCNF1 = (RADIO_PCNF1_WHITEEN_Disabled    << RADIO_PCNF1_WHITEEN_Pos) |
                           (RADIO_PCNF1_ENDIAN_Big          << RADIO_PCNF1_ENDIAN_Pos)  |
                           ((m_esb_addr.addr_length - 1)    << RADIO_PCNF1_BALEN_Pos)   |
                           (payload_length                  << RADIO_PCNF1_STATLEN_Pos) |
                           (payload_length                  << RADIO_PCNF1_MAXLEN_Pos);
    }
    

    Also looking at the NRF_ESB_PROTOCOL_ESB_DPL case in start_tx_transaction() might offer some clues. 

    static void start_tx_transaction()
    {
        bool ack;
    
        m_last_tx_attempts = 1;
        // Prepare the payload
        mp_current_payload = m_tx_fifo.p_payload[m_tx_fifo.exit_point];
    
    
        switch (m_config_local.protocol)
        {
            case NRF_ESB_PROTOCOL_ESB:
                update_rf_payload_format(mp_current_payload->length);
                m_tx_payload_buffer[0] = mp_current_payload->pid;
                m_tx_payload_buffer[1] = 0;
                memcpy(&m_tx_payload_buffer[2], mp_current_payload->data, mp_current_payload->length);
    
                NRF_RADIO->SHORTS   = m_radio_shorts_common | RADIO_SHORTS_DISABLED_RXEN_Msk;
                NRF_RADIO->INTENSET = RADIO_INTENSET_DISABLED_Msk | RADIO_INTENSET_READY_Msk;
    
                // Configure the retransmit counter
                m_retransmits_remaining = m_config_local.retransmit_count;
                on_radio_disabled = on_radio_disabled_tx;
                m_nrf_esb_mainstate = NRF_ESB_STATE_PTX_TX_ACK;
                break;
    
            case NRF_ESB_PROTOCOL_ESB_DPL:
                ack = !mp_current_payload->noack || !m_config_local.selective_auto_ack;
                m_tx_payload_buffer[0] = mp_current_payload->length;
                m_tx_payload_buffer[1] = mp_current_payload->pid << 1;
                m_tx_payload_buffer[1] |= mp_current_payload->noack ? 0x00 : 0x01;
                memcpy(&m_tx_payload_buffer[2], mp_current_payload->data, mp_current_payload->length);
    
                // Handling ack if noack is set to false or if selective auto ack is turned off
                if (ack)
                {
                    NRF_RADIO->SHORTS   = m_radio_shorts_common | RADIO_SHORTS_DISABLED_RXEN_Msk;
                    NRF_RADIO->INTENSET = RADIO_INTENSET_DISABLED_Msk | RADIO_INTENSET_READY_Msk;
    
                    // Configure the retransmit counter
                    m_retransmits_remaining = m_config_local.retransmit_count;
                    on_radio_disabled = on_radio_disabled_tx;
                    m_nrf_esb_mainstate = NRF_ESB_STATE_PTX_TX_ACK;
                }
                else
                {
                    NRF_RADIO->SHORTS   = m_radio_shorts_common;
                    NRF_RADIO->INTENSET = RADIO_INTENSET_DISABLED_Msk;
                    on_radio_disabled   = on_radio_disabled_tx_noack;
                    m_nrf_esb_mainstate = NRF_ESB_STATE_PTX_TX;
                }
                break;
    
            default:
                // Should not be reached
                break;
        }
    
        NRF_RADIO->TXADDRESS    = mp_current_payload->pipe;
        NRF_RADIO->RXADDRESSES  = 1 << mp_current_payload->pipe;
    
        NRF_RADIO->FREQUENCY    = m_esb_addr.rf_channel;
        NRF_RADIO->PACKETPTR    = (uint32_t)m_tx_payload_buffer;
    
        NVIC_ClearPendingIRQ(RADIO_IRQn);
        NVIC_EnableIRQ(RADIO_IRQn);
    
        NRF_RADIO->EVENTS_ADDRESS = 0;
        NRF_RADIO->EVENTS_PAYLOAD = 0;
        NRF_RADIO->EVENTS_DISABLED = 0;
    
        DEBUG_PIN_SET(DEBUGPIN4);
        NRF_RADIO->TASKS_TXEN  = 1;
    }
    

    Best regards

    Bjørn

Reply
  • Hi Cwmoreiras,

    just out of curiosity, why can't you use the ESB implementation in our SDK?  It is backwards compatible with the nRF24, see Backward compatibility

    Looking at our ESB implementation I found the following functions

    static void update_rf_payload_format_esb_dpl(uint32_t payload_length)
    {
    #if (NRF_ESB_MAX_PAYLOAD_LENGTH <= 32)
        // Using 6 bits for length
        NRF_RADIO->PCNF0 = (0 << RADIO_PCNF0_S0LEN_Pos) |
                           (6 << RADIO_PCNF0_LFLEN_Pos) |
                           (3 << RADIO_PCNF0_S1LEN_Pos) ;
    #else
        // Using 8 bits for length
        NRF_RADIO->PCNF0 = (0 << RADIO_PCNF0_S0LEN_Pos) |
                           (8 << RADIO_PCNF0_LFLEN_Pos) |
                           (3 << RADIO_PCNF0_S1LEN_Pos) ;
    #endif
        NRF_RADIO->PCNF1 = (RADIO_PCNF1_WHITEEN_Disabled    << RADIO_PCNF1_WHITEEN_Pos) |
                           (RADIO_PCNF1_ENDIAN_Big          << RADIO_PCNF1_ENDIAN_Pos)  |
                           ((m_esb_addr.addr_length - 1)    << RADIO_PCNF1_BALEN_Pos)   |
                           (0                               << RADIO_PCNF1_STATLEN_Pos) |
                           (NRF_ESB_MAX_PAYLOAD_LENGTH      << RADIO_PCNF1_MAXLEN_Pos);
    }
    
    
    static void update_rf_payload_format_esb(uint32_t payload_length)
    {
        NRF_RADIO->PCNF0 = (1 << RADIO_PCNF0_S0LEN_Pos) |
                           (0 << RADIO_PCNF0_LFLEN_Pos) |
                           (1 << RADIO_PCNF0_S1LEN_Pos);
    
        NRF_RADIO->PCNF1 = (RADIO_PCNF1_WHITEEN_Disabled    << RADIO_PCNF1_WHITEEN_Pos) |
                           (RADIO_PCNF1_ENDIAN_Big          << RADIO_PCNF1_ENDIAN_Pos)  |
                           ((m_esb_addr.addr_length - 1)    << RADIO_PCNF1_BALEN_Pos)   |
                           (payload_length                  << RADIO_PCNF1_STATLEN_Pos) |
                           (payload_length                  << RADIO_PCNF1_MAXLEN_Pos);
    }
    

    Also looking at the NRF_ESB_PROTOCOL_ESB_DPL case in start_tx_transaction() might offer some clues. 

    static void start_tx_transaction()
    {
        bool ack;
    
        m_last_tx_attempts = 1;
        // Prepare the payload
        mp_current_payload = m_tx_fifo.p_payload[m_tx_fifo.exit_point];
    
    
        switch (m_config_local.protocol)
        {
            case NRF_ESB_PROTOCOL_ESB:
                update_rf_payload_format(mp_current_payload->length);
                m_tx_payload_buffer[0] = mp_current_payload->pid;
                m_tx_payload_buffer[1] = 0;
                memcpy(&m_tx_payload_buffer[2], mp_current_payload->data, mp_current_payload->length);
    
                NRF_RADIO->SHORTS   = m_radio_shorts_common | RADIO_SHORTS_DISABLED_RXEN_Msk;
                NRF_RADIO->INTENSET = RADIO_INTENSET_DISABLED_Msk | RADIO_INTENSET_READY_Msk;
    
                // Configure the retransmit counter
                m_retransmits_remaining = m_config_local.retransmit_count;
                on_radio_disabled = on_radio_disabled_tx;
                m_nrf_esb_mainstate = NRF_ESB_STATE_PTX_TX_ACK;
                break;
    
            case NRF_ESB_PROTOCOL_ESB_DPL:
                ack = !mp_current_payload->noack || !m_config_local.selective_auto_ack;
                m_tx_payload_buffer[0] = mp_current_payload->length;
                m_tx_payload_buffer[1] = mp_current_payload->pid << 1;
                m_tx_payload_buffer[1] |= mp_current_payload->noack ? 0x00 : 0x01;
                memcpy(&m_tx_payload_buffer[2], mp_current_payload->data, mp_current_payload->length);
    
                // Handling ack if noack is set to false or if selective auto ack is turned off
                if (ack)
                {
                    NRF_RADIO->SHORTS   = m_radio_shorts_common | RADIO_SHORTS_DISABLED_RXEN_Msk;
                    NRF_RADIO->INTENSET = RADIO_INTENSET_DISABLED_Msk | RADIO_INTENSET_READY_Msk;
    
                    // Configure the retransmit counter
                    m_retransmits_remaining = m_config_local.retransmit_count;
                    on_radio_disabled = on_radio_disabled_tx;
                    m_nrf_esb_mainstate = NRF_ESB_STATE_PTX_TX_ACK;
                }
                else
                {
                    NRF_RADIO->SHORTS   = m_radio_shorts_common;
                    NRF_RADIO->INTENSET = RADIO_INTENSET_DISABLED_Msk;
                    on_radio_disabled   = on_radio_disabled_tx_noack;
                    m_nrf_esb_mainstate = NRF_ESB_STATE_PTX_TX;
                }
                break;
    
            default:
                // Should not be reached
                break;
        }
    
        NRF_RADIO->TXADDRESS    = mp_current_payload->pipe;
        NRF_RADIO->RXADDRESSES  = 1 << mp_current_payload->pipe;
    
        NRF_RADIO->FREQUENCY    = m_esb_addr.rf_channel;
        NRF_RADIO->PACKETPTR    = (uint32_t)m_tx_payload_buffer;
    
        NVIC_ClearPendingIRQ(RADIO_IRQn);
        NVIC_EnableIRQ(RADIO_IRQn);
    
        NRF_RADIO->EVENTS_ADDRESS = 0;
        NRF_RADIO->EVENTS_PAYLOAD = 0;
        NRF_RADIO->EVENTS_DISABLED = 0;
    
        DEBUG_PIN_SET(DEBUGPIN4);
        NRF_RADIO->TASKS_TXEN  = 1;
    }
    

    Best regards

    Bjørn

Children
No Data
Related