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

nRF24L01+ raises IRQ on PRX side only once

Hello,

I am frustrated by a pair of nRF24L01+ communicating with each other, where all the Enhanced ShockBurst features are enabled.

The PRX is initialised as follows:

****** nRF24L01+ register set ******
Register 0x00	=	0x0F
Register 0x01	=	0x3F
Register 0x02	=	0x3F
Register 0x03	=	0x01
Register 0x04	=	0x1F
Register 0x05	=	0x00
Register 0x06	=	0x26
Register 0x07	=	0x0E
Register 0x08	=	0x00
Register 0x09	=	0x00
Register 0x0A	=	0x01,	0x01,	0x42,	0xE7,	0xE7
Register 0x0B	=	0x02,	0x01,	0x42,	0xC2,	0xC2
Register 0x0C	=	0x03
Register 0x0D	=	0x04
Register 0x0E	=	0x05
Register 0x0F	=	0x06
Register 0x10	=	0x00,	0x01,	0x42,	0xE7,	0xE7
Register 0x11	=	0x00
Register 0x12	=	0x00
Register 0x13	=	0x00
Register 0x14	=	0x00
Register 0x15	=	0x00
Register 0x16	=	0x00
Register 0x17	=	0x11
Register 0x1C	=	0x3F
Register 0x1D	=	0x07

After the first message has been sent by the TRX, the PRX raises a RX_DS_READY-IRQ, its registers change to

****** nRF24L01+ register set ******
Register 0x07	=	0x40						// RX_DR interrupt, pipe number 0
Register 0x17	=	0x10						// RX FIFO not empty

The RX code then serves the hardware IRQ and (as a test) just resets the IRQ-condition and flushes the FIFO. After doing so the registers values are the same as after initialisation. The TRX signals a successful transmission, so it must have received the acknowledement by the PRX.

So long all is fine. But when the TRX sends the second message (same contents as the first one), no hardware IRQ, and no register changes happen on the PRX side. Nevertheless, the TRX signals a succuessful transmission :-O

The only way to get another message to be signalled by an IRQ seems to be to cut the voltage supply for the PRX and power it up again. Even a power-down per software does not suffice. After powering up the PRX again the same starts from the beginning: ONE message ...

Btw., I think there is no bug on the TRX side: when I power down the PRX the TRX signals an error when sending a message.

Do you have a clue what happens?

Best regards, Ralph

  • Hi,

    1. On the PTX side, are you setting "TX_ADDR" register equal to "RX_PW_P0"? If not, the auto-acking will not work properly.
    2. How are you clearing the STATUS (0x07) register? You should read the content, then write '1' to the bits to clear it; statusval = read_reg(STATUS); retval = write_reg(STATUS, statusval);

    Best regards Håkon

  • Yes Håkon, both conditions/procedures you named are fulfilled.

    What amazes me is the fact, that exactely this kind of communication already worked in another project (based on another architecture).

    And, as far as I can see, the inner state of the nRF24L01+ (i.e. its register contents) as well as its outer state (signal lines, namely CE) are identical when receiving the first message from the PTX and any following message. But nevertheless, there MUST be a difference anywhere...

    I am totally clueless :/

    Any further guesses/hints?

    Best regards Ralph

    In case you want to check for yourself:

    The PTX registers are:

    ****** nRF24L01+ register set ****** Register 0x00 = 0x0E Register 0x01 = 0x3F Register 0x02 = 0x01 Register 0x03 = 0x01 Register 0x04 = 0x2F Register 0x05 = 0x00 Register 0x06 = 0x26 Register 0x07 = 0x0E Register 0x08 = 0x00 Register 0x09 = 0x00 Register 0x0A = 0x01, 0x01, 0x42, 0xE7, 0xE7 Register 0x0B = 0xFF, 0xFF, 0x42, 0xC2, 0xC2 Register 0x0C = 0xFF Register 0x0D = 0xFF Register 0x0E = 0xFF Register 0x0F = 0xFF Register 0x10 = 0x01, 0x01, 0x42, 0xE7, 0xE7 Register 0x11 = 0x00 Register 0x12 = 0x00 Register 0x13 = 0x00 Register 0x14 = 0x00 Register 0x15 = 0x00 Register 0x16 = 0x00 Register 0x17 = 0x11 Register 0x1C = 0x3F Register 0x1D = 0x07

    I use only 3 address bytes, so (0x01, 0x01, 0x42) is the relevant part.

  • Hi,

    You should enable the PIPEs that you're using in registers RX_PW_Px on both sides. If these are set to '0' the pipe is not used. For the PTX it's usually only RX_PW_P0.

    Best regards Håkon

  • Hi,

    I have experienced the same issue possibly caused for the same reason hopefully this can save someone else time and sanity.

    I paired the problem back to a simple test case.

    Configure the TX and the RX with all default initialized values, i.e. PWR_UP = 1 and set CE = 1 and PRIM_RX = 0 on TX. Optionally you can enable Dynamic Payload Length and W_TX_PAYLOAD_NOACK command.

    When the TX sends a packet with or without ACK the RX will see the initial RX_DR interrupt.

    In my interrupt handler I was first reading and "clearing" via write of a 1 to the STATUS register bits

    uint8_t hal_nrf_get_clear_irq_flags(void)
    {
      return hal_nrf_write_reg(STATUS, (BIT_6|BIT_5|BIT_4)) & (BIT_6|BIT_5|BIT_4);
    }
    

    Then I was using the return value to determine the source of the interrupt. And handling it as follows:

    while (!hal_nrf_rx_fifo_empty())
    {
    	hal_nrf_read_rx_pload(pload);
    }
    
    radio_set_status (RF_RX_DR);
    

    The handler reads the payload into a buffer called pload and then sets a status flag when not more packets are in the RX fifo.

    NOTE: The astute will notice that this code can cause dropped packets. For the packet rate that I am using this is adequate. For higher speed rates this code fails.

    My MCU is basically in a sleep state awaiting an external interrupt. The interrupt from the NRF24L01P device wakes the MCU up and execution continues. In the MCUs code path post wake up I was doing the following:

    radio_status_t status = radio_get_status();
    			
    if(status == RF_RX_DR)
    {
    	uint16_t packet_info = hal_nrf_read_rx_pload((uint8_t *) &packet);
    

    The hal_nrf_read_rx_pload methods is defined as the following:

    uint16_t hal_nrf_read_rx_pload(uint8_t *rx_pload)
    {
      return hal_nrf_read_multibyte_reg(UINT8(HAL_NRF_RX_PLOAD), rx_pload);
    }
    

    The hal_nrf_read_multibyte_reg method executes the R_RX_PL_WID command to get the payload length and then reads the payload via the R_RX_PAYLOAD command.

    It is this sequence of reads that seems to put the NRF24L01P into a strange state whereby the TX gets an ACK but no interrupt occurs.

    Another behavior that I observed was that the TX will get an ACK for the first three packets and then transmission fails due to MAX_RT. This makes sense in light of the above as the RX is not clearing its FIFO because there are not interrupts being fired to the MCU to read the packet data.

    To resolve the problem I simply stopped reading from the receive payload registers, which was the source of this bug, and read from the payload buffer instead. Alternately I could have modified the interrupt code to simply set the status and allowed the MCU main like code to read the receive registers.

    Regards Derek

  • I'm not absolutely sure (because there MAY be other changes done during a somewhat longer development cycle), but most probably this solved the problem. Strange though, since this is not what someone would expect after having read the manual.

Related