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

How to speed up the change between PTX and PRX of esb?

Hi,

I am using 2 esb devices to test my packet send and received.

My use case is:

1. Node-1 and Node-2 is power-in in PRX mode

2. Node-1 switch to PTX and send a packet, then switch to PRX,

3. Node-2 receive packet, switch to PTX mode and send a packet out. After send packet, switch to PRX.

4. Node-1 receive packet, switch to PTX mode and send a packet out. After send packet, switch to PRX.

....

If the speed between PTX and PRX is to fast, then it will cause many "Send error".  If I add some delay (Ex: use nrf_delay_ms(2)), then there will no error occur.

What is the bottleneck? PTX switch to PRX? or PRX switch to PTX?

Thank you,

Chianglin

Parents
  • Hi Chianglin

    In principle it should take less than 200us to switch from PTX to PRX or vice versa. 

    The question is whether or not you are able to switch in sync. If the PTX has switched before the PRX then the packet you send will not be successfully received. 

    Are you using ACK's or retransmits?

    If you are using the retransmit feature then any lost packet should be automatically retransmitted, so that you don't see it as a packet loss. 

    Best regards
    Torbjørn

  • Hi Torbjørn,

    Actually, the ack function had been disable in my case.

    Please reference the attach file, there have two dependent project which need to download to two different device (name: Host and Node).

    #include <stdbool.h>
    #include <stdint.h>
    #include <string.h>
    #include "sdk_common.h"
    #include "nrf.h"
    #include "nrf_esb.h"
    #include "nrf_error.h"
    #include "nrf_esb_error_codes.h"
    #include "nrf_delay.h"
    #include "nrf_gpio.h"
    #include "boards.h"
    #include "nrf_delay.h"
    #include "app_util.h"
    #include "app_timer.h"
    #include "nrf_drv_gpiote.h"
    
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    
    #include "GpioProcess.h"
    #include "EsbProcess.h"
    
    #define	Host_SendBack										// �w�q�o���ܼ� -> Host ����ʥ]��, �|���@�U���e, �M��A�o�^�h
    
    unsigned long	PacketSendCnt = 0;
    unsigned long	PacketSendOKCnt = 0;
    unsigned long	PacketSentNGCnt = 0;
    unsigned long	PacketReceiveOKCnt = 0;
    unsigned long	PacketReceiveNGCnt = 0;
    
    void PacketSend(void)
    {
        int							i;
        uint8_t						Sum = 0;
    
    	//	printf(" ==> Send Packet back\r\n");
    #if 1
    	EebTxRxSwitch(TX);
    #else
    	(void) nrf_esb_stop_rx();
    	(void) nrf_esb_flush_tx();
    	(void) nrf_esb_start_tx();
    #endif
    	for (i = 1 ; i < NRF_ESB_MAX_PAYLOAD_LENGTH ; i++ )
    		Sum = Sum + tx_payload.data[i];
    	tx_payload.data[0] = Sum;
        tx_payload.noack = true;
        if (nrf_esb_write_payload(&tx_payload) == NRF_SUCCESS)
        {
            tx_payload.data[2]++;
        #ifdef	EsbTestUartEnsable
    		printf(" [%X %X %X %X %X %X %X %X]\r\n", tx_payload.length, tx_payload.pipe, tx_payload.rssi, tx_payload.noack, tx_payload.pid, tx_payload.data[0], tx_payload.data[1], tx_payload.data[2]);
        	printf(" Send. CheckSum =  %X\r\n", Sum);
            printf(" Send OK\r\n");
        #endif	// EsbTestUartEnsable
        }
        else
        {
            //	printf(" *** Sending packet failed");
        } 
    }
    
    long	RxLedFlashCnt = 0;
    void nrf_esb_event_handler(nrf_esb_evt_t const * p_event)
    {
        switch (p_event->evt_id)
        {
            case NRF_ESB_EVENT_TX_SUCCESS:
            	PacketSendOKCnt++;
            #ifdef	EsbTestUartEnsable
            	printf(" Change to RX\r\n");
            #endif	// EsbTestUartEnsable
            	EebTxRxSwitch(RX);
            	break;
            case NRF_ESB_EVENT_TX_FAILED:
            	//	printf(" TX-Err\r\n");
                (void) nrf_esb_flush_tx();
                (void) nrf_esb_start_tx();
                PacketSentNGCnt++;
                tx_payload.data[3]++;
                nrf_delay_ms(2);
                PacketSend();
                break;
            case NRF_ESB_EVENT_RX_RECEIVED:
            #ifdef	EsbTestUartEnsable
                printf("RX RECEIVED PAYLOAD\r\n");
            #endif	// EsbTestUartEnsable
                while (nrf_esb_read_rx_payload(&rx_payload) == NRF_SUCCESS)
                {
                #ifdef	Host_SendBack
                    if (rx_payload.length > 0)
                    {
    	            	uint8_t			Sum = 0;
                		int				i;
                		for ( i = 1 ; i < NRF_ESB_MAX_PAYLOAD_LENGTH ; i++ )
                			Sum = Sum + rx_payload.data[i];
    					if ( Sum == rx_payload.data[0] )
    					{
    						PacketReceiveOKCnt++;
    						//	printf(" I [%X]\r\n", Sum);
    						if ( ++RxLedFlashCnt == 50 )
    						{
    							RxLedFlashCnt = 0;
    							nrf_gpio_pin_toggle(GpioLed0);
    						}
    					}
    					else
    					{
    						PacketReceiveNGCnt++;
                        	printf(" *** Packet NG [%x]---\r\n", Sum);
                        }
                        // ���� PTX, �e�ʥ]
                        memcpy(tx_payload.data, rx_payload.data, rx_payload.length);
                        tx_payload.data[3]++;
                        nrf_delay_ms(2);
    					PacketSend();
    		            //	PacketSend(rx_payload.data[1]);
                    }
                #endif	// Host_SendBack
                }
                break;
        }
    }
    
    
    void clocks_start( void )
    {
        NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
        NRF_CLOCK->TASKS_HFCLKSTART = 1;
    
        while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0);
    }
    
    unsigned char	TriggerPressed = 0;
    unsigned char	TriggerPressedFlag = 0;
    
    // ---- APP_TIMER code added here ----
    APP_TIMER_DEF(m_esb_tx_timer_id);
    APP_TIMER_DEF(Timer_1S_timer_id);
    
    void Action_Key1(void)
    {
    	PacketSend();
    }
    	
    void esb_send_packet_timer_callback(void *p)
    {
    	PacketSend();
    }
    
    extern	uint8_t		KeyDebunseTick;
    void Timer_1S(void *p)
    {
    	static uint32_t		sPacketSendOKCnt, sPacketSentNGCnt, sPacketReceiveOKCnt, sPacketReceiveNGCnt;
    	printf(" TX: %d/%d, RX: %d/%d\r\n", (PacketSendOKCnt - sPacketSendOKCnt), (PacketSentNGCnt - sPacketSentNGCnt), (PacketReceiveOKCnt - sPacketReceiveOKCnt), (PacketReceiveNGCnt - sPacketReceiveNGCnt));
    	sPacketSendOKCnt = PacketSendOKCnt;
    	sPacketSentNGCnt = PacketSentNGCnt;
    	sPacketReceiveOKCnt = PacketReceiveOKCnt;
    	sPacketReceiveNGCnt = PacketReceiveNGCnt;
    }
    
    static void timers_init(void)
    {
    	ret_code_t err_code;
        
    	// Start the 32.768 kHz low frequency clock. Without this the app_timer module won't work
    	NRF_CLOCK->TASKS_LFCLKSTART = 1;
        
    	// Initialize timer module.
    	err_code = app_timer_init();
    	APP_ERROR_CHECK(err_code); 
    
    	// Create timers.
    	err_code = app_timer_create(&m_esb_tx_timer_id, APP_TIMER_MODE_REPEATED, esb_send_packet_timer_callback);
    	APP_ERROR_CHECK(err_code);
    	err_code = app_timer_create(&Timer_1S_timer_id, APP_TIMER_MODE_REPEATED, Timer_1S); 
    	APP_ERROR_CHECK(err_code);
    }
    
    static void timers_start(void)
    {
        ret_code_t err_code;
    #if 0
        err_code = app_timer_start(m_esb_tx_timer_id, APP_TIMER_TICKS(3000/*100*/), (void *)0);
        APP_ERROR_CHECK(err_code);
    #endif
        err_code = app_timer_start(Timer_1S_timer_id, APP_TIMER_TICKS(5000/*100*/), (void *)0);
        APP_ERROR_CHECK(err_code);
    }
    // -----------------------------------
    
    
    int main(void)
    {
        ret_code_t err_code;
    
        clocks_start();
        gpio_init();
        UART_Init();
        printf(" ... Start (TX) ...\r\n");
        timers_init();
        
        err_code = esb_init(RX);
        APP_ERROR_CHECK(err_code);
        err_code = nrf_esb_start_rx();
        APP_ERROR_CHECK(err_code);
    
        timers_start();
    
    	while(1)
    	{
            if(NRF_LOG_PROCESS() == false)
            {
                __WFE();
            }
    	}
        while (true)
        {
            // Nothing to do now that the app_timer runs everything, except flush the log and go to sleep
            if(NRF_LOG_PROCESS() == false)
            {
                __WFE();
            }
        }
    }
    

    #include <stdbool.h>
    #include <stdint.h>
    #include <string.h>
    #include "sdk_common.h"
    #include "nrf.h"
    #include "nrf_esb.h"
    #include "nrf_error.h"
    #include "nrf_esb_error_codes.h"
    #include "nrf_delay.h"
    #include "nrf_gpio.h"
    #include "boards.h"
    #include "nrf_delay.h"
    #include "app_util.h"
    #include "app_timer.h"
    
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    
    #include "GpioProcess.h"
    #include "EsbProcess.h"
    
    unsigned long	PacketSendCnt = 0;
    unsigned long	PacketSendOKCnt = 0;
    unsigned long	PacketSentNGCnt = 0;
    unsigned long	PacketReceiveOKCnt = 0;
    unsigned long	PacketReceiveNGCnt = 0;
    
    void PacketSend(void)
    {
        int							i;
        uint8_t						Sum = 0;
    
    	//	printf(" ==> Send Packet back\r\n");
    #if 1
    	EebTxRxSwitch(TX);
    #else
    	(void) nrf_esb_stop_rx();
    	(void) nrf_esb_flush_tx();
    	(void) nrf_esb_start_tx();
    #endif
    	for (i = 1 ; i < NRF_ESB_MAX_PAYLOAD_LENGTH ; i++ )
    		Sum = Sum + tx_payload.data[i];
    	tx_payload.data[0] = Sum;
        tx_payload.noack = true;
        if (nrf_esb_write_payload(&tx_payload) == NRF_SUCCESS)
        {
            tx_payload.data[2]++;
        #ifdef	EsbTestUartEnsable
    		printf(" [%X %X %X %X %X %X %X %X]\r\n", tx_payload.length, tx_payload.pipe, tx_payload.rssi, tx_payload.noack, tx_payload.pid, tx_payload.data[0], tx_payload.data[1], tx_payload.data[2]);
        	printf(" Send. CheckSum =  %X\r\n", Sum);
            printf(" Send OK\r\n");
        #endif	// EsbTestUartEnsable
            // Toggle one of the LEDs.
        }
        else
        {
            //	printf(" *** Sending packet failed");
        } 
    }
    
    void Action_Key1(void)
    {
    	PacketSend();
    }
    
    long	RxLedFlashCnt = 0;
    void nrf_esb_event_handler(nrf_esb_evt_t const * p_event)
    {
        switch (p_event->evt_id)
        {
            case NRF_ESB_EVENT_TX_SUCCESS:
            	PacketSendOKCnt++;
           	#ifdef	EsbTestUartEnsable
            	printf(" Change to RX\r\n");
            #endif	// EsbTestUartEnsable
                EebTxRxSwitch(RX);
                break;
            case NRF_ESB_EVENT_TX_FAILED:
                //	printf(" TX-Err\r\n");
                (void) nrf_esb_flush_tx();
                (void) nrf_esb_start_tx();
                PacketSentNGCnt++;
                tx_payload.data[3]++;
                nrf_delay_ms(2);
                PacketSend();
                break;
            case NRF_ESB_EVENT_RX_RECEIVED:
            #ifdef	EsbTestUartEnsable
                printf("RX RECEIVED EVENT\r\n");
            #endif	// EsbTestUartEnsable
                while (nrf_esb_read_rx_payload(&rx_payload) == NRF_SUCCESS)
                {
                    if (rx_payload.length > 0)
                    {
    	            	uint8_t			Sum = 0;
                		int				i;
                		for ( i = 1 ; i < NRF_ESB_MAX_PAYLOAD_LENGTH ; i++ )
                			Sum = Sum + rx_payload.data[i];
    					if ( Sum == rx_payload.data[0] )
    					{
    						PacketReceiveOKCnt++;
    						//	printf(" I [%X]\r\n", Sum);
    						if ( ++RxLedFlashCnt == 50 )
    						{
    							RxLedFlashCnt = 0;
    							nrf_gpio_pin_toggle(GpioLed0);
    						}
    					}
    					else
    					{
    						PacketReceiveNGCnt++;
                        	printf(" *** Packet NG [%x]---\r\n", Sum);
                        }
                        // Switch PTX, modify content, and send again
                        memcpy(tx_payload.data, rx_payload.data, rx_payload.length);
                        tx_payload.data[3]++;
                        nrf_delay_ms(2);
    					PacketSend();
    		            //	PacketSend(rx_payload.data[1]);
                    }
                }
                break;
        }
    }
    
    
    void clocks_start( void )
    {
        NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
        NRF_CLOCK->TASKS_HFCLKSTART = 1;
    
        while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0);
    }
    
    // ---- APP_TIMER code added here ----
    APP_TIMER_DEF(m_esb_tx_timer_id);
    APP_TIMER_DEF(Timer_1S_timer_id);
    
    static void esb_send_packet_timer_callback(void *p)
    {
        static nrf_esb_payload_t tx_payload = NRF_ESB_CREATE_PAYLOAD(0, 0x01, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00);
        printf("TX packet sent");
        tx_payload.noack = false;
        if (nrf_esb_write_payload(&tx_payload) == NRF_SUCCESS)
        {
            // Toggle one of the LEDs.
            nrf_gpio_pin_write(LED_1, !(tx_payload.data[1]%8>0 && tx_payload.data[1]%8<=4));
            nrf_gpio_pin_write(LED_2, !(tx_payload.data[1]%8>1 && tx_payload.data[1]%8<=5));
            nrf_gpio_pin_write(LED_3, !(tx_payload.data[1]%8>2 && tx_payload.data[1]%8<=6));
            nrf_gpio_pin_write(LED_4, !(tx_payload.data[1]%8>3));
            tx_payload.data[1]++;
        }
        else
        {
            printf("Sending packet failed");
        } 
    }
    
    extern	uint8_t		KeyDebunseTick;
    void Timer_1S(void *p)
    {
    	static uint32_t		sPacketSendOKCnt, sPacketSentNGCnt, sPacketReceiveOKCnt, sPacketReceiveNGCnt;
    	printf(" TX: %d/%d, RX: %d/%d\r\n", (PacketSendOKCnt - sPacketSendOKCnt), (PacketSentNGCnt - sPacketSentNGCnt), (PacketReceiveOKCnt - sPacketReceiveOKCnt), (PacketReceiveNGCnt - sPacketReceiveNGCnt));
    	sPacketSendOKCnt = PacketSendOKCnt;
    	sPacketSentNGCnt = PacketSentNGCnt;
    	sPacketReceiveOKCnt = PacketReceiveOKCnt;
    	sPacketReceiveNGCnt = PacketReceiveNGCnt;
    }
    
    static void timers_init(void)
    {
        ret_code_t err_code;
        
        // Start the 32.768 kHz low frequency clock. Without this the app_timer module won't work
        NRF_CLOCK->TASKS_LFCLKSTART = 1;
        
        // Initialize timer module.
        err_code = app_timer_init();
        APP_ERROR_CHECK(err_code); 
    
        // Create timers.
        err_code = app_timer_create(&m_esb_tx_timer_id, APP_TIMER_MODE_REPEATED, esb_send_packet_timer_callback);
        APP_ERROR_CHECK(err_code);    
    	err_code = app_timer_create(&Timer_1S_timer_id, APP_TIMER_MODE_REPEATED, Timer_1S); 
    	APP_ERROR_CHECK(err_code);
    }
    
    static void timers_start(void)
    {
        ret_code_t err_code;
    #if 0
        app_timer_start(m_esb_tx_timer_id, APP_TIMER_TICKS(2000/*100*/), (void *)0);
        APP_ERROR_CHECK(err_code);
    #endif
        err_code = app_timer_start(Timer_1S_timer_id, APP_TIMER_TICKS(5000/*100*/), (void *)0);
        APP_ERROR_CHECK(err_code);
    }
    // -----------------------------------
    
    int main(void)
    {
        uint32_t err_code;
    
        gpio_init();
    
        clocks_start();
    
        UART_Init();
        printf(" ... Start (RX) ...\r\n");
        timers_init();
    
        err_code = esb_init(RX);
        APP_ERROR_CHECK(err_code);
        err_code = nrf_esb_start_rx();
        APP_ERROR_CHECK(err_code);
    
    	timers_start();
    
        while (true)
        {
            // Nothing to do now that the app_timer runs everything, except flush the log and go to sleep
            if(NRF_LOG_PROCESS() == false)
            {
                __WFE();
            }
        }
    }
    

    The process procedure is:

    1. Press a button on Host, host will send a packet (use  PacketSend() to send packet in Host.c)

    2. Node will receive this packet (in line-88 of Node.c)

    3. Node delay 2 ms (use nrf_delay_ms(2)), modify the packet content and send again (line-119 of Node.c)

    4. Host will recerive the packet (in line-65 of Host.c)

    5. Host delay 2 ms (use nrf_delay_ms(2)),  modify the packet content and send again (line-117 of Host.c)

    6. Loop step 2 to 5

    If I reduce the delay in step 2 and 5 to 1ms, There will cause many TX-Error in these two node

    Would you please tell me how to modify this code, then I can speed-up the Packet transmit and receive?

    Thank you,

    Chianglin

  • Hi Torbjørn,

    Thank you for your support.

    Sorry, I don't have scope now, so I don't know the status of radio.

    Please find the attach file for my full porject.

    004.7z

    Thank you again.

    Chianglin

  • Hi Chianglin

    Possibly the problem is that you are using auto ACK while at the same time manually switching between PTX and PRX modes. 

    When using ACK you shouldn't have to switch back and forth PTX and PRX, you can just use the ACK payload feature to send data from the PRX to the PTX if you want to. 

    If for some reason you want to implement your own ACK scheme, and switch the radios between PTX and PRX, then it doesn't make sense to enable ACK's in the protocol. 

    I would recommend either disabling ACK's on all your packets, or avoid switching between PTX and PRX modes by using the ACK payload feature. 

    Best regards
    Torbjørn 

  • Hi Torbjørn,

    You are right, I don't want to use ACK function when ESB transfer/receive all of the time.

    I found there have a code which set the "noack" to faulse in line-144 of Node.c, It is my mistake.  But function "esb_send_packet_timer_callback()" will not execute, because timer "m_esb_tx_timer_id" doesn't enable.

    How to modify my program to speed-up the switch between PTX and PRX, If I want to disable ACK in ESB function?

    Thank you

    Chianglin

  • Hi Torbjørn,

    Do you have any comment about this issue?

    Thank you,

    Chianglin

  • Hi Chianglin

    Sorry for the late reply, I have been busy with travel and other things. 

    I will do a small test tomorrow and try to benchmark the TX/RX turnaround time. Once I know how fast it should be I can compare it to your results, and send you my test code. 

    Best regards
    Torbjørn

Reply Children
Related