Hi,
I am using the nRF52840 DK with SDK 17.0.2.
I am working on a project using the ESB protocol. In my design, an ACK packet is transmitted to the receiver every 5 seconds, controlled by an APP_TIMER.
However, I am encountering an issue related to retransmit_delay and retransmit_count. Even though I have configured these parameters, the transmitter does not perform any retransmissions or report TX_FAILED when the receiver does not acknowledge the packet. Instead, it simply sends the packet every 5 seconds until a fatal error occurs.
#define NRF_ESB_DEFAULT_CONFIG {.protocol = NRF_ESB_PROTOCOL_ESB_DPL, \
.mode = NRF_ESB_MODE_PTX, \
.event_handler = 0, \
.bitrate = NRF_ESB_BITRATE_2MBPS, \
.crc = NRF_ESB_CRC_16BIT, \
.tx_output_power = NRF_ESB_TX_POWER_8DBM, \
.retransmit_delay = 100, \
.retransmit_count = 3, \
.tx_mode = NRF_ESB_TXMODE_AUTO, \
.radio_irq_priority = 1, \
.event_irq_priority = 2, \
.payload_length = 32, \
.selective_auto_ack = false \
}
uint32_t esb_init(void)
{
uint32_t ret;
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.protocol = NRF_ESB_PROTOCOL_ESB_DPL;
nrf_esb_config.retransmit_count = 3;
nrf_esb_config.retransmit_delay = 100;
nrf_esb_config.bitrate = NRF_ESB_BITRATE_2MBPS;
nrf_esb_config.event_handler = nrf_esb_event_handler;
nrf_esb_config.mode = NRF_ESB_MODE_PTX;
nrf_esb_config.selective_auto_ack = true;
ret = nrf_esb_init(&nrf_esb_config);
VERIFY_SUCCESS(ret);
ret = nrf_esb_set_base_address_0(base_addr_0);
VERIFY_SUCCESS(ret);
ret = nrf_esb_set_base_address_1(base_addr_1);
VERIFY_SUCCESS(ret);
ret = nrf_esb_set_prefixes(addr_prefix, NRF_ESB_PIPE_COUNT);
VERIFY_SUCCESS(ret);
return ret;
}
This test was performed inside my project. When I test using the original ESB example, the TX correctly reports TX_FAILED when no ACK is received, but it still does not perform any retransmissions.
I traced the code into on_radio_disabled_tx_wait_for_ack, and I found that it does not continue triggering NRF_ESB_SYS_TIMER->CC[1] according to my configured retransmit_count.
For better readability, I am providing the relevant section of the on_radio_disabled_tx_wait_for_ack function below:
static void on_radio_disabled_tx_wait_for_ack()
{
NRF_LOG_ERROR("on_radio_disabled_tx_wait_for_ack");
// This marks the completion of a TX_RX sequence (TX with ACK)
// Make sure the timer will not deactivate the radio if a packet is received
NRF_PPI->CHENCLR = (1 << NRF_ESB_PPI_TIMER_START) |
(1 << NRF_ESB_PPI_RX_TIMEOUT) |
(1 << NRF_ESB_PPI_TIMER_STOP);
// If the radio has received a packet and the CRC status is OK
if (NRF_RADIO->EVENTS_END && NRF_RADIO->CRCSTATUS != 0)
{
NRF_LOG_ERROR("radio has received a packet and the CRC status is OK");
NRF_ESB_SYS_TIMER->TASKS_SHUTDOWN = 1;
NRF_PPI->CHENCLR = (1 << NRF_ESB_PPI_TX_START);
m_interrupt_flags |= NRF_ESB_INT_TX_SUCCESS_MSK;
m_last_tx_attempts = m_config_local.retransmit_count - m_retransmits_remaining + 1;
(void) nrf_esb_skip_tx();
if (m_config_local.protocol != NRF_ESB_PROTOCOL_ESB && m_rx_payload_buffer[0] > 0)
{
if (rx_fifo_push_rfbuf((uint8_t)NRF_RADIO->TXADDRESS, m_rx_payload_buffer[1] >> 1))
{
m_interrupt_flags |= NRF_ESB_INT_RX_DATA_RECEIVED_MSK;
}
}
if ((m_tx_fifo.count == 0) || (m_config_local.tx_mode == NRF_ESB_TXMODE_MANUAL))
{
m_nrf_esb_mainstate = NRF_ESB_STATE_IDLE;
NVIC_SetPendingIRQ(ESB_EVT_IRQ);
}
else
{
NVIC_SetPendingIRQ(ESB_EVT_IRQ);
start_tx_transaction();
}
}
else
{
if (m_retransmits_remaining-- == 0)
{
NRF_ESB_SYS_TIMER->TASKS_SHUTDOWN = 1;
NRF_PPI->CHENCLR = (1 << NRF_ESB_PPI_TX_START);
// All retransmits are expended, and the TX operation is suspended
m_last_tx_attempts = m_config_local.retransmit_count + 1;
m_interrupt_flags |= NRF_ESB_INT_TX_FAILED_MSK;
m_nrf_esb_mainstate = NRF_ESB_STATE_IDLE;
NVIC_SetPendingIRQ(ESB_EVT_IRQ);
}
else
{
// There are still more retransmits left, TX mode should be
// entered again as soon as the system timer reaches CC[1].
NRF_RADIO->SHORTS = m_radio_shorts_common | RADIO_SHORTS_DISABLED_RXEN_Msk;
update_rf_payload_format(mp_current_payload->length);
NRF_RADIO->PACKETPTR = (uint32_t)m_tx_payload_buffer;
on_radio_disabled = on_radio_disabled_tx;
m_nrf_esb_mainstate = NRF_ESB_STATE_PTX_TX_ACK;
NRF_ESB_SYS_TIMER->TASKS_START = 1;
NRF_PPI->CHENSET = (1 << NRF_ESB_PPI_TX_START);
if (NRF_ESB_SYS_TIMER->EVENTS_COMPARE[1])
{
NRF_RADIO->TASKS_TXEN = 1;
}
}
}
}
If I enable the RX, the code does enter the final section of on_radio_disabled_tx_wait_for_ack, where the comment says “There are still more retransmits left, TX mode should be entered again as soon as the system timer reaches CC[1].”. In this part, I logged the value of m_last_tx_attempts and confirmed that it is 1. However, NRF_RADIO->TASKS_TXEN = 1; is never triggered, even though retransmissions should still be pending.
What is even more confusing is that when I enable the RX, the receiver does send back a valid ACK, but the transmitter does not enter the code path under if (m_retransmits_remaining-- == 0) nor the following section of code that I have pasted below.
if (NRF_RADIO->EVENTS_END && NRF_RADIO->CRCSTATUS != 0)
{
NRF_LOG_ERROR("radio has received a packet and the CRC status is OK");
NRF_ESB_SYS_TIMER->TASKS_SHUTDOWN = 1;
NRF_PPI->CHENCLR = (1 << NRF_ESB_PPI_TX_START);
m_interrupt_flags |= NRF_ESB_INT_TX_SUCCESS_MSK;
m_last_tx_attempts = m_config_local.retransmit_count - m_retransmits_remaining + 1;
(void) nrf_esb_skip_tx();
if (m_config_local.protocol != NRF_ESB_PROTOCOL_ESB && m_rx_payload_buffer[0] > 0)
{
if (rx_fifo_push_rfbuf((uint8_t)NRF_RADIO->TXADDRESS, m_rx_payload_buffer[1] >> 1))
{
m_interrupt_flags |= NRF_ESB_INT_RX_DATA_RECEIVED_MSK;
}
}
if ((m_tx_fifo.count == 0) || (m_config_local.tx_mode == NRF_ESB_TXMODE_MANUAL))
{
m_nrf_esb_mainstate = NRF_ESB_STATE_IDLE;
NVIC_SetPendingIRQ(ESB_EVT_IRQ);
}
else
{
NVIC_SetPendingIRQ(ESB_EVT_IRQ);
start_tx_transaction();
}
}
which should be executed when a packet with a valid CRC is received.
This unexpected behavior makes me unsure why the TX neither follows the retransmission path nor the CRC-OK ACK reception path.
I would like to ask whether any modifications are required in the ESB source code in order to make the retransmission mechanism work properly?
If you could help identify what I might be doing wrong, I would greatly appreciate it.
Thank you!