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

Loss of connection between rf24 transmitter & receiver

Loss of comms between nRF24L01+ transmitter and receiver after successful data transfer.

One rf24 is configured as a PTX (sensor device) communicating in a simple point-point link with a second in PRX mode (base unit) over pipe 0. Both are connected to a small

microcomputer (not an Arduino). Example Code used for them to ping-pong between each other works well. But modified code when used in this Tx ->Rx mode fails after a random period?

My intended operational mode is for the PTX to send a radio code when a sensor is triggered - which could be every few minutes to every few hours.  At first this works on the bench with

PTX and PRX side by side, but despite a sequence of successful transmissions over a period between 5 minutes to 30 minutes, the PTX generally freezes first, sometime it's the Base PRX

which freezes first.  So my code seems to work ok until it suddendly doesn't. As far as I can tell, my code correctly implements the RF24 state diagrams, the registers appear to be correctly 

configured and the TX-FIFO & RX-FIFO are flushed as necessary. After device power up I do leave the PTX in Tx mode and the PRX in Rx mode the whole time and don't set the

power-down but? This random freezing of communication suggests a timing issue somewhere, but I've tried various code modifications without success. 

Question: Could there be an un-documented issue with these radios that may explain the sudden freezing of communication after a sequence of good operation, or am I missing

sometime more obvious.  Your help would be greatly appreciated!

I can send the configs if there's not an obvious answer.

thanks

Parents
  • HI Håkon,

    Thank you for replying today (Tuesday 6/4/21).  As you can probably guess, I've no previous experience with these radios and I don't have the means (or understanding how)  to send the state of the rf24 registers when the communication freezes. Sorry!  In answer to your points today:

    1) OK, so there's no link as such... I feel like I have to assume that the CRCs are ok as data does flow successfully until all stops. I don't know how to prove otherwise.  I initialise the RF24s in RF channel 108...could this matter?

    2) my code doesn't do anything specific with the interrupts except the Rx code polls for receipt using the subroutine:

    def any_rx():

        return not bool(reg_read(FIFO_STATUS,nop) & RX_EMPTY) # Lo if data in FIFO

    3) Over the last weekend, I lost confidence in, my code, so I reverted to code that "ping-pongs" brief 4 byte messages between the PTX & PRX at regular intervals...which I kept increasing until the communication froze again (it got up to about 40 mins). Perhaps my code is flushing buffers at the wrong time and this eventually causes the comms to freeze.  I simply don't know? But, as you can see with the above subroutine, my code is checking the FIFO_STATUS.

    The code that follows is my 'ping-pong' code - the same code for the PTX and PRX microcomputers but a button press on each device at start up determines which RF24 starts the sequence as PTX and which starts as PRX.  Maybe you can spot  where my code is in error.....obviously this code is as simple as I can make it.

    *** SUGGESTION ***

    You've kindly spent some  time looking at my code, but would it be more efficient in your time/effort if you could send me some example code (based on the simple code format that I'm trying to use here) which I imagine you engineers must have which demonstrates the very simple point-point communication that I'm trying to achieve?  That way I could hopefully work out where my lack of understanding is by comparing the code and minimize wasting your time.

    ___________________________________________

    Here's my simple 'ping-pong' code:

    # nRF24L01+ registers:

    CONFIG = const(0x00)

    EN_AA = const(0x01)

    EN_RXADDR = const(0x02)

    SETUP_AW = const(0x03)

    SETUP_RETR = const(0x04)

    RF_CH = const(0x05)

    RF_SETUP = const(0x06)

    STATUS = const(0x07)

    RX_ADDR_P0 = const(0x0A)

    TX_ADDR = const(0x10)

    RX_PW_P0 = const(0x11)

    FIFO_STATUS = const(0x17)

    DYNPD = const(0x1C)

    # CONFIG:

    EN_CRC = const(0x08)

    CRCO = const(0x04)

    PWR_UP = const(0x02)

    PRIM_RX = const(0x01)

    # STATUS register

    RX_DR = const(0x40)         # RX data ready; write 1 to clear

    TX_DS = const(0x20)         # TX data sent; write 1 to clear

    MAX_RT = const(0x10)        # max retransmits reached; write 1 to clear

    # FIFO_STATUS register

    RX_EMPTY = const(0x01)      # 1 if RX FIFO is empty

    # constants for instructions

    R_RX_PL_WID = const(0x60)   # read RX payload width

    R_RX_PAYLOAD = const(0x61)  # read RX payload

    W_TX_PAYLOAD = const(0xA0)  # write TX payload

    FLUSH_TX = const(0xE1)      # flush TX FIFO

    FLUSH_RX = const(0xE2)      # flush RX FIFO

    nop = const(0xFF)           # use to read registers

    payload_size = const(0x04)      # 4 bytes for ping-pong tests

    channel = const(0x6C)           # chan 108 - above WIFI chans

    A1 = b'\x78\x78\x78\x78\x78'    # data pipe0 address

                                # 0x7878787878 - doesn't work

    # my buffers:

    buf_out = bytearray(1)

    buf_in = bytearray(1)

    rx_buf = bytearray(payload_size)

    def init_radio():

        utime.sleep_ms(5)

        reg_write(SETUP_AW,0b11)    # addr width to 5 bytes

        res = reg_read(SETUP_AW,nop)

        if res != 0b11:

            display.scroll("E1")    # check comms with hw

            sleep(1000)

        reg_write(EN_AA,0x01)       # enable auto ack on pipe0 only

        #reg_write(SETUP_RETR,0x68)  # auto re-tx delay 1750us & count 8

        reg_write(SETUP_RETR,0xFF)  # auto re-tx delay 4ms & count 15 attempts

        reg_write(RF_CH,0x6C)       # rf chan 108

        reg_write(RF_SETUP, 0x22)   # 250KB, -12dBm low power

        #reg_write(RF_SETUP, 0x26)   # 250KB, 0dBm  max power

        reg_write(DYNPD,0)          # disable dynamic payloads

        set_crc(2)                  # CRC 2 bytes

        reg_write(STATUS,RX_DR|TX_DS|MAX_RT)    # clr flags

        flush_rx()

        flush_tx()

       

    def flush_rx():

        buf_out[0] = FLUSH_RX

        pin16.write_digital(0)

        spi.write_readinto(buf_out,buf_in)

        pin16.write_digital(1)

       

    def flush_tx():

        buf_out[0] = FLUSH_TX

        pin16.write_digital(0)

        spi.write_readinto(buf_out,buf_in)

        pin16.write_digital(1)

     

    def set_crc(length):

        config = reg_read(CONFIG,nop) & ~(CRCO | EN_CRC)

        if length == 0:

            pass

        elif length == 1:

            config |= EN_CRC

        else:

            config |= EN_CRC | CRCO

        reg_write(CONFIG, config)

       

    def open_tx_pipe(addr):

        #EN_AA & SETUP_AW already set in init_radio for pipe0 & 5 byte addr width

        # reg_write(EN_RXADDR,0x01)           # enable data pipe0

        reg_write(RX_PW_P0,payload_size)    # RX payload bytes in pipe0

        reg_write_bytes(RX_ADDR_P0,addr)    # set pipe0 rx addr

        reg_write_bytes(TX_ADDR,addr)       # set tx addr to same

     

    def open_rx_pipe(addr):

        #EN_AA & SETUP_AW already set in init_radio fro pipe0 & 5 byte addr width

        reg_write(EN_RXADDR,0x01)           # enable data pipe 0

        reg_write(RX_PW_P0,payload_size)    # RX payload bytes in pipe0

        reg_write_bytes(RX_ADDR_P0,addr)    # set pipe0 rx addr

        # reg_write_bytes(TX_ADDR,addr)       # set tx addr to same

       

    def start_send(data):

        # transmit pipe0 should already be set up

        reg_write(CONFIG,(reg_read(CONFIG,nop) | PWR_UP))   # set PUP

        sleep(2)                    # wait for 1.5msec start up time

        # now in Standby-I mode

        reg_write(CONFIG,(reg_read(CONFIG,nop) & ~PRIM_RX)) # set TX mode

        utime.sleep_us(150)         # wait for TX setting time

        load_TX_FIFO(data)

        # now transmit data

        pin12.write_digital(1)      ### set CE for Active Tx Mode ###

        utime.sleep_us(15)          # needs to be >10us

        pin12.write_digital(0)      ### reset CE Chip Enable ###

     

    def end_send():

        # end send mode

        reg_write(STATUS,RX_DR|TX_DS|MAX_RT)                # clr flags

        reg_write(CONFIG,reg_read(CONFIG,nop) | PRIM_RX)    # Set RX mode

        reg_write(CONFIG,reg_read(CONFIG,nop) & ~PWR_UP)    # power down

        flush_rx()

        flush_tx()

     

    def start_listening():

        # receive pipe0 should already be set up

        reg_write(CONFIG,reg_read(CONFIG,nop) | PWR_UP)     # PUP

        sleep(2)                # wait for >1.5 msec

        # now in Standby-I mode

        reg_write(CONFIG,reg_read(CONFIG,nop) | PRIM_RX)    # Set RX mode

        reg_write(STATUS,RX_DR|TX_DS|MAX_RT)                # clr flags extra

        flush_rx()              # needed?

        flush_tx()              # needed?

        pin12.write_digital(1)  ### set CE Chip Enable to start active RX mode ###

        utime.sleep_us(150)     # wait Rx setting time

       

    def stop_listening():

        pin12.write_digital(0)  ### reset CE Chip Enable ###

        utime.sleep_us(150)

        # returned to Standby-I mode

        reg_write(STATUS,RX_DR|TX_DS|MAX_RT)   # clr flags extra

        flush_rx()

        flush_tx()

     

    def any_rx():

        return not bool(reg_read(FIFO_STATUS,nop) & RX_EMPTY) # Lo if data in FIFO

     

    def receive(reg,rx_buf):

        buf_out[0] = reg

        pin16.write_digital(0)              # CS Lo

        spi.write_readinto(buf_out,buf_in)  # send reg

        rx_buf = spi.read(payload_size)     # get code

        pin16.write_digital(1)              # CS Hi

        reg_write(STATUS,RX_DR)

        return rx_buf

        # now ready for entering TX or RX mode or power down mode

     

    def p_out(code):

        # Enter Tx mode:

        open_tx_pipe(A1)

        stop_listening()

        sleep(1000)     # wait for receiver to display previously received msg

        display.show(">")

        sleep(500)

        display.clear()

        start_send(code)

        end_send()

     

    def p_in():

        open_rx_pipe(A1)

        start_listening()

        while not any_rx():

            utime.sleep_us(10)

        res = receive(R_RX_PAYLOAD,rx_buf)

        display.scroll(str(res,'UTF-8'))

       

    # Initialise:

    init_SPI()

    init_radio()

    if button_b.is_pressed():   # using input as Tx/Rx mode selection

        PRX = True

    else:

        PRX = False

       

    if not PRX:

        display.show('t')

        sleep(3000)

        display.clear()

    else:

        display.show('r')

        sleep(3000)

        display.clear()

     

    while True:

        # Main loop does one full ping-pong cycle

        if not PRX:

            # start as PTX

            p_out("ping")    # send ping

            p_in()           # go into receive mode and wait for reply

        else:

            # start as PRX

            p_in()           # receive and display msg

            p_out("pong")    # send pong

        sleep(10)      #    delay before starting next ping-pong cycle

    _____________________________________________________ 

    It's the last line - sleep() which I increase until the comms freezes.

    If you're unable to send me some example code, then I hope that you can spot what I'm doing wrong!

    Kind Regards

    Mike Byrne 

Reply
  • HI Håkon,

    Thank you for replying today (Tuesday 6/4/21).  As you can probably guess, I've no previous experience with these radios and I don't have the means (or understanding how)  to send the state of the rf24 registers when the communication freezes. Sorry!  In answer to your points today:

    1) OK, so there's no link as such... I feel like I have to assume that the CRCs are ok as data does flow successfully until all stops. I don't know how to prove otherwise.  I initialise the RF24s in RF channel 108...could this matter?

    2) my code doesn't do anything specific with the interrupts except the Rx code polls for receipt using the subroutine:

    def any_rx():

        return not bool(reg_read(FIFO_STATUS,nop) & RX_EMPTY) # Lo if data in FIFO

    3) Over the last weekend, I lost confidence in, my code, so I reverted to code that "ping-pongs" brief 4 byte messages between the PTX & PRX at regular intervals...which I kept increasing until the communication froze again (it got up to about 40 mins). Perhaps my code is flushing buffers at the wrong time and this eventually causes the comms to freeze.  I simply don't know? But, as you can see with the above subroutine, my code is checking the FIFO_STATUS.

    The code that follows is my 'ping-pong' code - the same code for the PTX and PRX microcomputers but a button press on each device at start up determines which RF24 starts the sequence as PTX and which starts as PRX.  Maybe you can spot  where my code is in error.....obviously this code is as simple as I can make it.

    *** SUGGESTION ***

    You've kindly spent some  time looking at my code, but would it be more efficient in your time/effort if you could send me some example code (based on the simple code format that I'm trying to use here) which I imagine you engineers must have which demonstrates the very simple point-point communication that I'm trying to achieve?  That way I could hopefully work out where my lack of understanding is by comparing the code and minimize wasting your time.

    ___________________________________________

    Here's my simple 'ping-pong' code:

    # nRF24L01+ registers:

    CONFIG = const(0x00)

    EN_AA = const(0x01)

    EN_RXADDR = const(0x02)

    SETUP_AW = const(0x03)

    SETUP_RETR = const(0x04)

    RF_CH = const(0x05)

    RF_SETUP = const(0x06)

    STATUS = const(0x07)

    RX_ADDR_P0 = const(0x0A)

    TX_ADDR = const(0x10)

    RX_PW_P0 = const(0x11)

    FIFO_STATUS = const(0x17)

    DYNPD = const(0x1C)

    # CONFIG:

    EN_CRC = const(0x08)

    CRCO = const(0x04)

    PWR_UP = const(0x02)

    PRIM_RX = const(0x01)

    # STATUS register

    RX_DR = const(0x40)         # RX data ready; write 1 to clear

    TX_DS = const(0x20)         # TX data sent; write 1 to clear

    MAX_RT = const(0x10)        # max retransmits reached; write 1 to clear

    # FIFO_STATUS register

    RX_EMPTY = const(0x01)      # 1 if RX FIFO is empty

    # constants for instructions

    R_RX_PL_WID = const(0x60)   # read RX payload width

    R_RX_PAYLOAD = const(0x61)  # read RX payload

    W_TX_PAYLOAD = const(0xA0)  # write TX payload

    FLUSH_TX = const(0xE1)      # flush TX FIFO

    FLUSH_RX = const(0xE2)      # flush RX FIFO

    nop = const(0xFF)           # use to read registers

    payload_size = const(0x04)      # 4 bytes for ping-pong tests

    channel = const(0x6C)           # chan 108 - above WIFI chans

    A1 = b'\x78\x78\x78\x78\x78'    # data pipe0 address

                                # 0x7878787878 - doesn't work

    # my buffers:

    buf_out = bytearray(1)

    buf_in = bytearray(1)

    rx_buf = bytearray(payload_size)

    def init_radio():

        utime.sleep_ms(5)

        reg_write(SETUP_AW,0b11)    # addr width to 5 bytes

        res = reg_read(SETUP_AW,nop)

        if res != 0b11:

            display.scroll("E1")    # check comms with hw

            sleep(1000)

        reg_write(EN_AA,0x01)       # enable auto ack on pipe0 only

        #reg_write(SETUP_RETR,0x68)  # auto re-tx delay 1750us & count 8

        reg_write(SETUP_RETR,0xFF)  # auto re-tx delay 4ms & count 15 attempts

        reg_write(RF_CH,0x6C)       # rf chan 108

        reg_write(RF_SETUP, 0x22)   # 250KB, -12dBm low power

        #reg_write(RF_SETUP, 0x26)   # 250KB, 0dBm  max power

        reg_write(DYNPD,0)          # disable dynamic payloads

        set_crc(2)                  # CRC 2 bytes

        reg_write(STATUS,RX_DR|TX_DS|MAX_RT)    # clr flags

        flush_rx()

        flush_tx()

       

    def flush_rx():

        buf_out[0] = FLUSH_RX

        pin16.write_digital(0)

        spi.write_readinto(buf_out,buf_in)

        pin16.write_digital(1)

       

    def flush_tx():

        buf_out[0] = FLUSH_TX

        pin16.write_digital(0)

        spi.write_readinto(buf_out,buf_in)

        pin16.write_digital(1)

     

    def set_crc(length):

        config = reg_read(CONFIG,nop) & ~(CRCO | EN_CRC)

        if length == 0:

            pass

        elif length == 1:

            config |= EN_CRC

        else:

            config |= EN_CRC | CRCO

        reg_write(CONFIG, config)

       

    def open_tx_pipe(addr):

        #EN_AA & SETUP_AW already set in init_radio for pipe0 & 5 byte addr width

        # reg_write(EN_RXADDR,0x01)           # enable data pipe0

        reg_write(RX_PW_P0,payload_size)    # RX payload bytes in pipe0

        reg_write_bytes(RX_ADDR_P0,addr)    # set pipe0 rx addr

        reg_write_bytes(TX_ADDR,addr)       # set tx addr to same

     

    def open_rx_pipe(addr):

        #EN_AA & SETUP_AW already set in init_radio fro pipe0 & 5 byte addr width

        reg_write(EN_RXADDR,0x01)           # enable data pipe 0

        reg_write(RX_PW_P0,payload_size)    # RX payload bytes in pipe0

        reg_write_bytes(RX_ADDR_P0,addr)    # set pipe0 rx addr

        # reg_write_bytes(TX_ADDR,addr)       # set tx addr to same

       

    def start_send(data):

        # transmit pipe0 should already be set up

        reg_write(CONFIG,(reg_read(CONFIG,nop) | PWR_UP))   # set PUP

        sleep(2)                    # wait for 1.5msec start up time

        # now in Standby-I mode

        reg_write(CONFIG,(reg_read(CONFIG,nop) & ~PRIM_RX)) # set TX mode

        utime.sleep_us(150)         # wait for TX setting time

        load_TX_FIFO(data)

        # now transmit data

        pin12.write_digital(1)      ### set CE for Active Tx Mode ###

        utime.sleep_us(15)          # needs to be >10us

        pin12.write_digital(0)      ### reset CE Chip Enable ###

     

    def end_send():

        # end send mode

        reg_write(STATUS,RX_DR|TX_DS|MAX_RT)                # clr flags

        reg_write(CONFIG,reg_read(CONFIG,nop) | PRIM_RX)    # Set RX mode

        reg_write(CONFIG,reg_read(CONFIG,nop) & ~PWR_UP)    # power down

        flush_rx()

        flush_tx()

     

    def start_listening():

        # receive pipe0 should already be set up

        reg_write(CONFIG,reg_read(CONFIG,nop) | PWR_UP)     # PUP

        sleep(2)                # wait for >1.5 msec

        # now in Standby-I mode

        reg_write(CONFIG,reg_read(CONFIG,nop) | PRIM_RX)    # Set RX mode

        reg_write(STATUS,RX_DR|TX_DS|MAX_RT)                # clr flags extra

        flush_rx()              # needed?

        flush_tx()              # needed?

        pin12.write_digital(1)  ### set CE Chip Enable to start active RX mode ###

        utime.sleep_us(150)     # wait Rx setting time

       

    def stop_listening():

        pin12.write_digital(0)  ### reset CE Chip Enable ###

        utime.sleep_us(150)

        # returned to Standby-I mode

        reg_write(STATUS,RX_DR|TX_DS|MAX_RT)   # clr flags extra

        flush_rx()

        flush_tx()

     

    def any_rx():

        return not bool(reg_read(FIFO_STATUS,nop) & RX_EMPTY) # Lo if data in FIFO

     

    def receive(reg,rx_buf):

        buf_out[0] = reg

        pin16.write_digital(0)              # CS Lo

        spi.write_readinto(buf_out,buf_in)  # send reg

        rx_buf = spi.read(payload_size)     # get code

        pin16.write_digital(1)              # CS Hi

        reg_write(STATUS,RX_DR)

        return rx_buf

        # now ready for entering TX or RX mode or power down mode

     

    def p_out(code):

        # Enter Tx mode:

        open_tx_pipe(A1)

        stop_listening()

        sleep(1000)     # wait for receiver to display previously received msg

        display.show(">")

        sleep(500)

        display.clear()

        start_send(code)

        end_send()

     

    def p_in():

        open_rx_pipe(A1)

        start_listening()

        while not any_rx():

            utime.sleep_us(10)

        res = receive(R_RX_PAYLOAD,rx_buf)

        display.scroll(str(res,'UTF-8'))

       

    # Initialise:

    init_SPI()

    init_radio()

    if button_b.is_pressed():   # using input as Tx/Rx mode selection

        PRX = True

    else:

        PRX = False

       

    if not PRX:

        display.show('t')

        sleep(3000)

        display.clear()

    else:

        display.show('r')

        sleep(3000)

        display.clear()

     

    while True:

        # Main loop does one full ping-pong cycle

        if not PRX:

            # start as PTX

            p_out("ping")    # send ping

            p_in()           # go into receive mode and wait for reply

        else:

            # start as PRX

            p_in()           # receive and display msg

            p_out("pong")    # send pong

        sleep(10)      #    delay before starting next ping-pong cycle

    _____________________________________________________ 

    It's the last line - sleep() which I increase until the comms freezes.

    If you're unable to send me some example code, then I hope that you can spot what I'm doing wrong!

    Kind Regards

    Mike Byrne 

Children
  • Hi Mike,

     

    mikebyrne said:

    while True:

        # Main loop does one full ping-pong cycle

        if not PRX:

            # start as PTX

            p_out("ping")    # send ping

            p_in()           # go into receive mode and wait for reply

        else:

            # start as PRX

            p_in()           # receive and display msg

            p_out("pong")    # send pong

        sleep(10)      #    delay before starting next ping-pong cycle

     p_in() function seems to be blocking until it receives a payload. Are you sure its not stuck in that utime.sleep()?

    If the PTX misses a payload, then the whole logic seems to go into a bad state where both act as PRX awaiting a PING/PONG from each other. If you can read back the registers on both devices, you should be able to check if my hypothesis is correct or not.

    Alternative can be to check the current consumption of each nRF-radio when it enters the bad state. If both show ~13 mA, then they're likely in RX.

     

    Note that there's a possibility to use "ACK payload" to piggy back information back to the PTX device, from the PRX device. How to enable and use this feature is mentioned more in-depth in the nRF24L01+ datasheet, chapter 7.4.1. If you look into this option, you do not have to switch the roles every time, but you would have to send in total two payloads to the PRX device (one for preparing the ACK payload, and one for fetching the ACK payload).

     

    mikebyrne said:
    You've kindly spent some  time looking at my code, but would it be more efficient in your time/effort if you could send me some example code (based on the simple code format that I'm trying to use here) which I imagine you engineers must have which demonstrates the very simple point-point communication that I'm trying to achieve?  That way I could hopefully work out where my lack of understanding is by comparing the code and minimize wasting your time.

    The nRF24L01+ is a pure SPI based radio transceiver, which means that you can hook it up to any platform that has SPI master capabilities and start controlling it. This is also one of the drawbacks when me and you are debugging, meaning that there's so many different possibilities of host controllers that is capable of driving the nRF24L01+. The code that we have is in the nRFgo SDK, and uses a common C based API for the whole nRF24L-series devices, while you are using a python based API on your own system.

    I could provide you a algorithm, but it would be much faster if we debug specifically towards your implemented platform.

     

    Kind regards,

    Håkon

  • Dear Håkon,

    Thank you again for spending the time on this with me - I really do appreciate it !

    To answer your points:

    i) One of your previous points was "Those routines seems to flush RX + TX FIFOs, then also clear all interrupt flags" - I'm unclear as to whether you think that this was good or bad?

    ii) I guess that the p_in() function could block if a non-ideal packet is received...so I will change my Receive code on this (see below)

    iii) I don't know what would make my PTX miss a payload send, but I take your point. I'm not yet sure whether I can easily change my coding to test your hypothesis above... still thinking on this!  However, as this code is representative of my intended application, (PTX sends 'data_out' & PRX responds with 'data_back')  I could think about setting a timer within the Receive loop to escape the loop if the return 'pong' has not been received within an acceptable time.

    iv) Yes, I did notice the ACK payload"  option in the data sheet, but I don't feel that I want to go there yet.

    v) Thanks for your comment about an algorithm, but I think that you're right, let's stay with trying to debug my code for now.

    My next step:

    Taking on your helpful comments, I will re-code to do the following and let you know how I get on (this might take me a couple of days!):

    1) I will select and fix the CRC at start up and remove my "set_CRC()" subr - just to eliminate this as a potential problem source.  I don't understand the case between using 1 or 2 CRC bytes (perhaps you might know?) but I will use the latter.

    2) My code has been responding to the INTERRUPT using the RX_EMPTY bit in FIFO_STATUS in subr "any_rx()", so I'll change this to use the RX_DR bit in STATUS.

    3) I will also re-code to reflect the full RX handling procedure described in the RF24 datasheet's table 27, STATUS register footnote (c), which I now realise I didn't implement fully. This should deal with more than one RX packet per Interrupt.

    4) My Receive code has not been using R_RX_PL_WID to check packet width, even though my code only ever transmits 3 or 4 bytes at a time, but I will now add this check into my receive subroutines in case an event somehow produces > 32 bytes and causes a problem

    Kind Regards,

    Mike Byrne

  • Hi Mike,

     

     

    mikebyrne said:
    i) One of your previous points was "Those routines seems to flush RX + TX FIFOs, then also clear all interrupt flags" - I'm unclear as to whether you think that this was good or bad?

     My apologies, that is good.

    mikebyrne said:
    iii) I don't know what would make my PTX miss a payload send, but I take your point. I'm not yet sure whether I can easily change my coding to test your hypothesis above... still thinking on this!  However, as this code is representative of my intended application, (PTX sends 'data_out' & PRX responds with 'data_back')  I could think about setting a timer within the Receive loop to escape the loop if the return 'pong' has not been received within an acceptable time.

    Wireless applications will lose a packet every now and then. This is true for all wireless protocols; wifi, bluetooth, GPS, satellite TV, etc.

    You do not need to change your code to test the scenario; you need to reproduce the issue and examine the registers state and/or check the current consumption of the nRF radio using a ampere-meter.

    If the issue is reproduced and identified; you can move on to solving the issue in code.

     

    Note that this is not an issue on the receiver side logic, but on the transmitter side logic, which assumes that it will receive a packet every time it sends one. Its OK that you continuously poll the status (or FIFO_STATUS) register to see if you have received a payload on a primary receiver, as it is expected that this one shall be in RX most of its life-time.

     

    mikebyrne said:

    iv) Yes, I did notice the ACK payload"  option in the data sheet, but I don't feel that I want to go there yet.

    Good that you were aware of this! It is a logical next step if you need bidirectional communication, but I understand that you want to take this step-by-step.

      

    mikebyrne said:
    1) I will select and fix the CRC at start up and remove my "set_CRC()" subr - just to eliminate this as a potential problem source.  I don't understand the case between using 1 or 2 CRC bytes (perhaps you might know?) but I will use the latter.

     1 byte = 256 combinations

    2 byte = 256*256 combinations

     

    2 byte is much stronger in terms of getting a random matching CRC. I would strongly recommend that you use 2 byte CRC.

    mikebyrne said:

    2) My code has been responding to the INTERRUPT using the RX_EMPTY bit in FIFO_STATUS in subr "any_rx()", so I'll change this to use the RX_DR bit in STATUS.

     If you choose to check the STATUS or the FIFO_STATUS register, it does not make a huge difference when you are polling the nRF radio.

    Its usually a bit more convenient to use the STATUS register, as it is shifted back on MISO by-default.

    mikebyrne said:
    3) I will also re-code to reflect the full RX handling procedure described in the RF24 datasheet's table 27, STATUS register footnote (c), which I now realise I didn't implement fully. This should deal with more than one RX packet per Interrupt.

     Good! Given that you flush the FIFOs after each reception, your logic handles this scenario eventually; but I guess you're interested in the other payloads that might be queued up as well.

    mikebyrne said:
    4) My Receive code has not been using R_RX_PL_WID to check packet width, even though my code only ever transmits 3 or 4 bytes at a time, but I will now add this check into my receive subroutines in case an event somehow produces > 32 bytes and causes a problem

    You seem to have dynamic payload length disabled, and use a static length.

    While I always recommend to have this check implemented (precaution for when you choose to enable dynamic payload length) ; it should not have caused any troubles for you, as you currently use a static payload length.

     

     

    mikebyrne said:
    I will re-code to do the following and let you know how I get on (this might take me a couple of days!)

     Let me know how it goes!

     

    Cheers,

    Håkon

  • Dear Håkon,

    It seems that my re-coding has worked and I now have a working system!  I made several changes that resulted in this but, unfortunately because of time pressure, I can’t be sure whether one change in particular did the trick or just the whole combination of minor changes.

    I’ve stopped using the ping-pong format and have made my Sensor_unit a dedicated PTX and the Base_unit a dedicated PRX. This avoided the possibility of the TX missing a response from the RX in the infinite loop example of the ping-pong sequence.

    1) Code changes to the PTX:

    - in former “p_out()” subroutine (subr), I swopped the order of  the open_tx_pipe(A1) and stop_listening() subrs (so that Open now proceeds Stop).  I don’t know whether this had any effect, but please comment if it could have.

    2) Code changes to the Rx:

    - the unnecessary CRC() subr was removed, with CRC for 2 bytes set in the init_radio() subr.

    - I changed the any_rx() subr from interrupt scanning on the RX_EMPTY bit in FIFO_STATUS to scanning on the RX_DR bit in STATUS.

    - in former “p_in()” subr, I (a) swopped the order of  the open_tx_pipe(A1) and stop_listening() subrs (so that Open now proceeds Stop), (b) added a check on the received packet length to be <32 bytes using R_RX_PL_WID with a break out of the infinite loop if >32, (c) encapsulated the Receive() subr  in a loop testing for more than 1 received payload per interrupt  .. by using a loop test on RX_EMPTY in FIFO_STATUS.

    I therefore note that for my code to have started working, is that my PTX completes a (PWR_UP & PTX) state mode followed by a (PWR_DOWN & PRX) state mode cycle.  Whereas my PRX always stays in a (PWR_UP & PRX) state mode.  Of course, it’s possible that further code modification might also be successful, but I don’t have the time to explore further.

    Thank you again for your detailed interest and help!!

    PS – once my particular nRF24L01+ application has been completed, I might investigate using some of your other similar products, so I would find a copy of your algorithm for the C based API for the whole nRF24L-series devices very helpful if your offer is still valid.

     

     

     

     

  • Hi Mike,

     

    I am glad to hear that the problems have disappeared!

     

    mikebyrne said:
    - in former “p_out()” subroutine (subr), I swopped the order of  the open_tx_pipe(A1) and stop_listening() subrs (so that Open now proceeds Stop).  I don’t know whether this had any effect, but please comment if it could have.

    You normally want to configure the device before starting the specific mode (it being TX or RX). For this specific routine, it does not matter much.

     

    mikebyrne said:

    - the unnecessary CRC() subr was removed, with CRC for 2 bytes set in the init_radio() subr.

    - I changed the any_rx() subr from interrupt scanning on the RX_EMPTY bit in FIFO_STATUS to scanning on the RX_DR bit in STATUS.

    - in former “p_in()” subr, I (a) swopped the order of  the open_tx_pipe(A1) and stop_listening() subrs (so that Open now proceeds Stop), (b) added a check on the received packet length to be <32 bytes using R_RX_PL_WID with a break out of the infinite loop if >32, (c) encapsulated the Receive() subr  in a loop testing for more than 1 received payload per interrupt  .. by using a loop test on RX_EMPTY in FIFO_STATUS.

    I therefore note that for my code to have started working, is that my PTX completes a (PWR_UP & PTX) state mode followed by a (PWR_DOWN & PRX) state mode cycle.  Whereas my PRX always stays in a (PWR_UP & PRX) state mode.  Of course, it’s possible that further code modification might also be successful, but I don’t have the time to explore further.

    Thank you again for your detailed interest and help!!

     Always happy to help!

    Good to hear that you added checks for handling the dynamic payload approach. This will save you debugging hours in the future.

     

    mikebyrne said:
    PS – once my particular nRF24L01+ application has been completed, I might investigate using some of your other similar products, so I would find a copy of your algorithm for the C based API for the whole nRF24L-series devices very helpful if your offer is still valid.

     Its just a simplistic API, and the real work is getting the logic up-and-running, with catching the corner-cases (like >32 byte payload), which the API does not show. I would recommend that you stick with the setup that you already have running, and rather contact us if any issues/questions  pop up.

     

    Cheers,

    Håkon

Related