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

ESB RX pipe incorrect

I have found an issue with ESB/Nordic radio where it will receive a packet on the wrong pipe. I think the issue occurs when the prefix array set to the PREFIX registers contains the same prefix twice, even if that prefix is unused according to the mask in RXADDRESSES.

To demonstrate, I added some static variables to nrf_esb.c:

static uint8_t pipe_rx = 0;
static uint8_t rx_count = 0;
static uint32_t addresses[5];

Near the bottom of on_radio_disabled_rx, where it adds the rx packet to the fifo:

if (rx_fifo_push_rfbuf(NRF_RADIO->RXMATCH, p_pipe_info->pid))
        {
            pipe_rx = NRF_RADIO->RXMATCH;
            rx_count++;
            addresses[0] = NRF_RADIO->BASE0;
            addresses[1] = NRF_RADIO->BASE1;
            addresses[2] = NRF_RADIO->PREFIX0;
            addresses[3] = NRF_RADIO->PREFIX1;
            addresses[4] = NRF_RADIO->RXADDRESSES;
            m_interrupt_flags |= NRF_ESB_INT_RX_DATA_RECEIVED_MSK;
            NVIC_SetPendingIRQ(ESB_EVT_IRQ);
        }

And in ESB_EVT_IRQHandler:

if (interrupts & NRF_ESB_INT_RX_DATA_RECEIVED_MSK)
        {
            NRF_LOG_INFO("Base 0 %02X:%02X:%02X:%02X", m_esb_addr.base_addr_p0[0], m_esb_addr.base_addr_p0[2], m_esb_addr.base_addr_p0[2], m_esb_addr.base_addr_p0[3]);
            NRF_LOG_INFO("Base 1 %02X:%02X:%02X:%02X", m_esb_addr.base_addr_p1[0], m_esb_addr.base_addr_p1[2], m_esb_addr.base_addr_p1[2], m_esb_addr.base_addr_p1[3]);
            NRF_LOG_INFO("Prefixes %d %02X:%02X:%02X", m_esb_addr.num_pipes, m_esb_addr.pipe_prefixes[0], m_esb_addr.pipe_prefixes[1], m_esb_addr.pipe_prefixes[2]);
            NRF_LOG_INFO("Pipe rx %d count %d", pipe_rx, rx_count);
            NRF_LOG_INFO("BASE0 %08X BASE1 %08X PREFIX0 %08X PREFIX1 %08X RXADDRESSES %08X", addresses[0], addresses[1], addresses[2], addresses[3], addresses[4]);
            rx_count--;
            pipe_rx = 0;
            event.evt_id = NRF_ESB_EVENT_RX_RECEIVED;
            m_event_handler(&event);
        }

Then initialise as PRX and set prefixes like so:

// ...other esb setup here
uint8_t prefixes[8] = {0x01, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00};
nrf_esb_set_prefixes(prefixes, 3); // ensures 0x02 is copied into internal esb buffer twice
nrf_esb_set_prefixes(prefixes, 2);
nrf_esb_start_rx();

Here the 0x02 prefix will be copied into the radio registers twice, however the second 0x02 register should be excluded by the mask set to NRF_RADIO->RXADDRESSES. However, it isn't. It seems the prefixes are compared in reverse order, and so the second 0x02 prefix is used as the pipe (pipe 2) instead of the first. Pipe 2 should not exist, but this is the value in RXMATCH when receiving a packet with prefix 0x02. These logs are produced (here I'm using 0x01 in place of 0x02):

00> [00:01:15.356,445] <info> app: Base 0 2F:A8:A8:F2
00> [00:01:15.356,567] <info> app: Base 1 CD:0D:0D:85
00> [00:01:15.356,750] <info> app: Prefixes 2 0F:01:01
00> [00:01:15.356,872] <info> app: Pipe rx 2 count 1
00> [00:01:15.357,025] <info> app: BASE0 F40B154F BASE1 B37FB0A1 PREFIX0 238080F0 PREFIX1 13E363A3 RXADDRESSES 00000003

You can see that the ESB prefixes array contains two 0x01 prefixes, and these have been copied into the NRF_RADIO registers. Additionally, the RXADDRESSES mask has been set, but is not being applied, because a packet is received on pipe 2.

The workaround/fix is to zero the prefix array in nrf_esb_set_prefixes:

memcpy(m_esb_addr.pipe_prefixes, p_prefixes, num_pipes);
    memset(m_esb_addr.pipe_prefixes + num_pipes, 0, sizeof(m_esb_addr.pipe_prefixes) - num_pipes);
    m_esb_addr.num_pipes = num_pipes;

Related