Electrical – Unable to flush TX FIFO queue of NRF24L01+

freertosmicrocontrollernrf24l01

I am writing code for an ESP32 to send data using a NRF24L01+ module to another NRF24L01+ module connected to an Arduino Pro Mini. The Arduino can successfully send data to the ESP32. So everything is properly wired up and the RF settings are compatible. However, when I switch roles, no packets are received on the Arduino and all transmitted packets set the MAX_RT (maximum retries reached) flag in the status register (on the ESP32 side).

The strangest thing is that I'm unable to flush the TX FIFO queue, which one is supposed to do to continue with the next package. Sending 0xE1 to the RF module seems to have no effect. After three failed packets, both the STATUS and the FIFO_STATUS register indicate TX FIFO full. And no amount of flush commands can clear it.

Question: Why does the FLUSH_TX command have no effect?

The code is written in C for the ESP32 SDK (aka ESP32 IDF) based on FreeRTOS. The communication is a simple unidirectional communication: either end is either sender or receiver only.

I've already ruled out many things:

  • I have verified the SPI communication with a logic analyzer and not found a problem.
  • I have compared the SPI communication of the ESP32 to the Arduino and they are almost identical. Main differences: timing; and ESP32 code stores configuration registers in memory to reduce number of register reads.
  • I have swapped the NRF24L01+ modules with no effect.
  • I have added a 47µF capacitor between GND and VCC close to the RF module.

Here's a dump of most of the registers:

STATUS = 0x0f: RX_DR=0 TX_DS=0 MAX_RT=0 RX_P_NO=1 TX_FULL=1
FIFO_STATUS = 0x21
RX_ADDR_P0 = 0x38a8bb7201
RX_ADDR_P1 = 0x389f30cc1b
RX_ADDR_P2-5 = 0xc3 0xc4 0xc5 0xc6
TX_ADDR = 0x38a8bb7201
RX_PW_P0-6 = 0x20 0x20 0x00 0x00 0x00 0x00
EN_AA = 0x3f
EN_RXADDR = 0x03
SETUP_AW = 0x03
REG_SETUP_RETR = 0x5f
RF_CH = 0x52
RF_SETUP = 0x03
CONFIG = 0x0e
DYNPD/FEATURE = 0x00 0x00

Best Answer

After I had invested many, many hours into problem analysis, I wrote the above question – only to figure it out about one hour later.

The problem turned out to be the SPI timing, more specifically the time between the falling edge of the SPI clock (SCK) for the last bit of the transaction and the rising edge of the chip select (CS). It was 0 but should be at least 2ns.

Invalid SPI timing for NRF24L01+:

SPI timing violation

Fixed SPI timing:

Fixed SPI timing

In the code, it's just one additional line, namely the line setting cs_ena_posttrans:

spi_device_interface_config_t device_config = {
    .clock_speed_hz = 1000000,
    .mode = 0,
    .spics_io_num = CSN_PIN,
    .command_bits = 8,
    .cs_ena_posttrans = 2
};

This not only fixes the FLUSH_TX command; transmitting packets works as well.