Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs

Replace ESP32/nRF24 with nRF52

My previous post and the response I got was hugely helpful to my understanding ESB on the nRF52. Now that I grasp the basics, I felt it was appropriate to create a new post for additional questions.

I continue to struggle to replace my PIC & ESP32/nRF24 combination with a nRF52. I have a rudimentary grasp of how ESB should work on the nRF52. However, I am not having any success implementing it.

For my setup I have two ESP32/nRF24 combinations. A dedicated Transmitter and a dedicated Receiver successfully communicating. Therefore, I can confirm my Transmitter Setup and that I understand the addressing and setup requirements. I am using the proven/dedicated ESP32 Transmitter to send.

I programmed the nRF52 (using the nRF5 because that’s the setup information I have, and I don’t want to introduce additional variables).

I have tried to leave the prx code unedited as much as possible except to make the appropriate configuration changes and disable "NRF_LOG_DEFERRED 0". Most of the changes are to esb_init().

I believe I have set the nRF52 setup correctly to be the Receiver, however __WFE() never seems to fire, so no Event is triggered.

I would love for someone to point out where I am making my mistake(s). Otherwise, I am at a dead end. I have included source code for the nRF52 and ESP32.

Here is the output/settings for my ESP32/nRF24 Transmitter:

17:16:53.958 -> SPI Frequency = 10 Mhz
17:16:53.958 -> Channel = 40 (~ 2440 MHz)
17:16:53.958 -> RF Data Rate = 1 MBPS
17:16:53.958 -> RF Power Amplifier = PA_MAX
17:16:53.958 -> RF Low Noise Amplifier = Enabled
17:16:53.992 -> CRC Length = 8 bits
17:16:53.992 -> Address Length = 5 bytes
17:16:53.992 -> Static Payload Length = 32 bytes
17:16:53.992 -> Auto Retry Delay = 1500 microseconds
17:16:53.992 -> Auto Retry Attempts = 15 maximum
17:16:53.992 -> Packets lost on
17:16:53.992 -> current channel = 0
17:16:53.992 -> Retry attempts made for
17:16:53.992 -> last transmission = 0
17:16:53.992 -> Multicast = Disabled
17:16:53.992 -> Custom ACK Payload = Disabled
17:16:53.992 -> Dynamic Payloads = Disabled
17:16:53.992 -> Auto Acknowledgment = Disabled
17:16:53.992 -> Primary Mode = TX
17:16:54.026 -> TX address = 0xc2c2c2c2c2
17:16:54.026 -> pipe 0 ( open ) bound = 0xc2c2c2c2c2
17:16:54.026 -> pipe 1 ( open ) bound = 0xe7e7e7e7e7
17:16:54.026 -> pipe 2 (closed) bound = 0xc3
17:16:54.026 -> pipe 3 (closed) bound = 0xc4
17:16:54.026 -> pipe 4 (closed) bound = 0xc5
17:16:54.026 -> pipe 5 (closed) bound = 0xc6

#include "nrf_esb.h"

#include <stdbool.h>
#include <stdint.h>
#include "sdk_common.h"
#include "nrf.h"
#include "nrf_esb_error_codes.h"
#include "nrf_delay.h"
#include "nrf_gpio.h"
#include "nrf_error.h"
#include "boards.h"

#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"


uint8_t led_nr;

nrf_esb_payload_t rx_payload;

/*lint -save -esym(40, BUTTON_1) -esym(40, BUTTON_2) -esym(40, BUTTON_3) -esym(40, BUTTON_4) -esym(40, LED_1) -esym(40, LED_2) -esym(40, LED_3) -esym(40, LED_4) */

void nrf_esb_event_handler(nrf_esb_evt_t const * p_event)
{
    switch (p_event->evt_id)
    {
        case NRF_ESB_EVENT_TX_SUCCESS:
            NRF_LOG_DEBUG("TX SUCCESS EVENT");
            break;
        case NRF_ESB_EVENT_TX_FAILED:
            NRF_LOG_DEBUG("TX FAILED EVENT");
            break;
        case NRF_ESB_EVENT_RX_RECEIVED:
            NRF_LOG_DEBUG("RX RECEIVED EVENT");
            if (nrf_esb_read_rx_payload(&rx_payload) == NRF_SUCCESS)
            {
                // Set LEDs identical to the ones on the PTX.
                nrf_gpio_pin_write(LED_1, !(rx_payload.data[1]%8>0 && rx_payload.data[1]%8<=4));
                nrf_gpio_pin_write(LED_2, !(rx_payload.data[1]%8>1 && rx_payload.data[1]%8<=5));
                nrf_gpio_pin_write(LED_3, !(rx_payload.data[1]%8>2 && rx_payload.data[1]%8<=6));
                nrf_gpio_pin_write(LED_4, !(rx_payload.data[1]%8>3));

                NRF_LOG_DEBUG("Receiving packet: %02x", rx_payload.data[1]);
            }
            break;
    }
}


void clocks_start( void )
{
    NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
    NRF_CLOCK->TASKS_HFCLKSTART = 1;

    while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0);
}


void gpio_init( void )
{
    bsp_board_init(BSP_INIT_LEDS);
}


uint32_t esb_init( void )
{
    uint32_t err_code;
    uint8_t base_addr_0[4] = {0xE7, 0xE7, 0xE7, 0xE7};
    uint8_t base_addr_1[4] = {0xC2, 0xC2, 0xC2, 0xC2};
    uint8_t addr_prefix[8] = {0xE7, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8 };

    //nrf_esb_config_t nrf_esb_config         = NRF_ESB_DEFAULT_CONFIG;
    //nrf_esb_config.payload_length           = 8;
    //nrf_esb_config.protocol                 = NRF_ESB_PROTOCOL_ESB_DPL;
    //nrf_esb_config.bitrate                  = NRF_ESB_BITRATE_2MBPS;
    //nrf_esb_config.mode                     = NRF_ESB_MODE_PRX;
    //nrf_esb_config.event_handler            = nrf_esb_event_handler;
    //nrf_esb_config.selective_auto_ack       = false;

    
    // OVERWRITE NRF_ESB_DEFAULT_CONFIG
    nrf_esb_config_t nrf_esb_config         = NRF_ESB_DEFAULT_CONFIG;
    nrf_esb_config.protocol                 = NRF_ESB_PROTOCOL_ESB;
    nrf_esb_config.mode                     = NRF_ESB_MODE_PRX;
    nrf_esb_config.event_handler            = nrf_esb_event_handler;
    nrf_esb_config.bitrate                  = NRF_ESB_BITRATE_1MBPS;
    nrf_esb_config.crc                      = NRF_ESB_CRC_8BIT;
    nrf_esb_config.tx_output_power          = NRF_ESB_TX_POWER_4DBM;
    nrf_esb_config.payload_length           = 32;
    nrf_esb_config.selective_auto_ack       = false;

    //err_code = nrf_esb_set_address_length(5); // causes: HardFault_Handler
    err_code = nrf_esb_set_rf_channel(40);    // overwrite default 2

    err_code = nrf_esb_init(&nrf_esb_config);
    VERIFY_SUCCESS(err_code);

    err_code = nrf_esb_set_base_address_0(base_addr_0);
    VERIFY_SUCCESS(err_code);

    err_code = nrf_esb_set_base_address_1(base_addr_1);
    VERIFY_SUCCESS(err_code);

    err_code = nrf_esb_set_prefixes(addr_prefix, 8);
    VERIFY_SUCCESS(err_code);

    return err_code;
}


int main(void)
{
    uint32_t err_code;

    /* Configure board. */
    gpio_init();

    err_code = NRF_LOG_INIT(NULL);
    APP_ERROR_CHECK(err_code);

    NRF_LOG_DEFAULT_BACKENDS_INIT();

    int counter = 0;
    NRF_LOG_INFO("NRF INFO");

    clocks_start();

    err_code = esb_init();
    APP_ERROR_CHECK(err_code);

    NRF_LOG_INFO("Enhanced ShockBurst Receiver Example started.");

    err_code = nrf_esb_start_rx();
    APP_ERROR_CHECK(err_code);

    while (true)
    {
        bsp_board_led_invert(LED_3); // THIS DOES NOT WORK!?
        bsp_board_led_invert(2); // THIS WORKS.

        if (NRF_LOG_PROCESS() == false)
        {
            bsp_board_led_invert(3); //LED flashes
            __WFE(); // WAIT FOR EVENT, NEVER FIRES. SYSTEM STOPS HERE.
        }
        //nrf_delay_ms(500); // FOR TESTING LEDS ONLY!
    }
}
/*lint -restore */

  • Excellent idea! Before jumping to the 52840, I edited the code on the two pca10040s. I enabled the modifications line by line and am 100% sure it is NRF_ESB_PROTOCOL_ESB causing the problem. Everything works fine with the following settings until I switch NRF_ESB_PROTOCOL_ESB_DPL to NRF_ESB_PROTOCOL_ESB.

        nrf_esb_config_t nrf_esb_config         = NRF_ESB_LEGACY_CONFIG;
        //nrf_esb_config.protocol                 = NRF_ESB_PROTOCOL_ESB_DPL;
        nrf_esb_config.protocol                 = NRF_ESB_PROTOCOL_ESB; // doesn't like this.
        nrf_esb_config.retransmit_delay         = 600;
        nrf_esb_config.bitrate                  = NRF_ESB_BITRATE_1MBPS;
        nrf_esb_config.crc                      = NRF_ESB_CRC_8BIT;
        nrf_esb_config.tx_output_power          = NRF_ESB_TX_POWER_4DBM;
        nrf_esb_config.payload_length           = 32;
        err_code = nrf_esb_set_rf_channel(40); 
        VERIFY_SUCCESS(err_code);
    
        nrf_esb_config.event_handler            = nrf_esb_event_handler;
        nrf_esb_config.mode                     = NRF_ESB_MODE_PRX;
        nrf_esb_config.selective_auto_ack       = false;
    
        err_code = nrf_esb_init(&nrf_esb_config);
        VERIFY_SUCCESS(err_code);

    It looks like the protocol is already set to NRF_ESB_PROTOCOL_ESB in the definition of NRF_ESB_LEGACY_CONFIG, so I tried just commenting out both protocol lines, but that didn't work.

    //nrf_esb_config.protocol = NRF_ESB_PROTOCOL_ESB_DPL;
    //nrf_esb_config.protocol = NRF_ESB_PROTOCOL_ESB; // doesn't like this.

    {.protocol = NRF_ESB_PROTOCOL_ESB, \
    .mode = NRF_ESB_MODE_PTX, \
    .event_handler = 0, \
    .bitrate = NRF_ESB_BITRATE_2MBPS, \
    .tx_output_power = NRF_ESB_TX_POWER_0DBM, \
    .retransmit_delay = 600, \
    .retransmit_count = 3, \
    .tx_mode = NRF_ESB_TXMODE_AUTO, \
    .radio_irq_priority = 1, \
    .event_irq_priority = 2, \
    .payload_length = 32, \
    .selective_auto_ack = false \
    }
    Also, I don't know if this is significant, but I noticed that the jumpers were different on the two boards (see image). Reset/Detect is not jumper'd on the second board. As far as I know this is how it came from the factory. I didn't move them and I am the only one with access to the boards.


    Is this the problem (see bold)? I will check the receiver against a running nrf24 tomorrow...

    Backward compatibility

    The Enhanced ShockBurst library is compatible with the legacy nRFgo SDK. To ensure that your application built with the nRF Connect SDK can communicate with nRF24 devices that run applications built with the nRFgo SDK, use the configuration ESB_LEGACY_CONFIG.

    Note, however, that the provided samples in the two SDKs do not correspond, so that you cannot use the Transmitter sample from one SDK with the Receiver sample from the other SDK.

  • The only way I could get communication from the ESP32/nRF24 to pca10040 was by enabling DynamicPayloads. Although it works I would love to know if there is a way to not enable DynamicPayloads and still get communication to work...

    ESP32 code

      radio.setChannel( 0x28 ); //2440
      radio.setAutoAck( false );
      radio.setCRCLength( RF24_CRC_8 );
      radio.setPALevel(RF24_PA_MAX);
      radio.setDataRate(RF24_1MBPS);
      radio.enableDynamicPayloads();

    nRF code

    uint32_t esb_init( void )
    {
        uint32_t err_code;
    
        // RECEIVER (1) ---
        uint8_t base_addr_0[4] = {0xE7, 0xE7, 0xE7, 0xE7};
        uint8_t base_addr_1[4] = {0xC2, 0xC2, 0xC2, 0xC2};
        uint8_t addr_prefix[8] = {0xE7, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8 };
    
    
        // RECEIVER ---
        nrf_esb_config_t nrf_esb_config         = NRF_ESB_LEGACY_CONFIG;
    
        nrf_esb_config.protocol                 = NRF_ESB_PROTOCOL_ESB_DPL;
        //nrf_esb_config.protocol                 = NRF_ESB_PROTOCOL_ESB; // doesn't like this.
    
        nrf_esb_config.retransmit_delay         = 600;
        nrf_esb_config.bitrate                  = NRF_ESB_BITRATE_1MBPS;
        nrf_esb_config.crc                      = NRF_ESB_CRC_8BIT;
        nrf_esb_config.tx_output_power          = NRF_ESB_TX_POWER_4DBM;
        nrf_esb_config.payload_length           = 32;
        err_code = nrf_esb_set_rf_channel(40); 
        VERIFY_SUCCESS(err_code);
    
        nrf_esb_config.event_handler            = nrf_esb_event_handler;
        nrf_esb_config.mode                     = NRF_ESB_MODE_PRX;
        nrf_esb_config.selective_auto_ack       = false;
    
        err_code = nrf_esb_init(&nrf_esb_config);
        VERIFY_SUCCESS(err_code);
    
        err_code = nrf_esb_set_base_address_0(base_addr_0);
        VERIFY_SUCCESS(err_code);
    
        err_code = nrf_esb_set_base_address_1(base_addr_1);
        VERIFY_SUCCESS(err_code);
    
        err_code = nrf_esb_set_prefixes(addr_prefix, 8);
        VERIFY_SUCCESS(err_code);
    
        return err_code;
    }

  • Hi,

    Good to hear it's working.

    You might need to set selective_auto_ack to true for that. 

    Also this post might be helpful:  ESB ACK packet not received? 

  • The ESB module treats ACK packets the same regardless of a payload contained within. And since dynamic payloads are required for ACK packets that have payloads, the dynamic payloads feature is required for basic auto-ack functionality (even when not using an ACK payload).

    In our RF24 Arduino library (for the nRF24L01), we use static payloads with auto-ack enabled as defaults for better OTA compatibility with counterfeit/clone chips. This seems to be an exploit of the nRF24L01 firmware though as successful use of these defaults contradict what the nRF24L01 datasheet says about auto-ack functionality (which I think is meant to refer to auto-ack with payloads).

  • Thank you for your reply! I appreciate your insight. The RF24 Arduino library you worked on was very instrumental to our understanding the nRF24 device in both the Arduino IDE and subsequently on PIC MCU's. And now again understanding how to use it with the nRF52. I can't tell you how much I appreciate it!

    Our devices help to reduce stress and heart attacks in fire fighters. We are now in additional government studies to further examine the health benefits. Creating these devices might not have been possible, certainly would have been more difficult, without the RF24 Arduino library you created. Thanks!

    -mike

    https://www.easealert.com/

Related