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

Timeslot API: BLE + ESB, slower transmissions when no advertising or no connection

Good morning everyone,

I am facing an apparently common problem (reported with some variations HereHere or here ) which is driving me crazy. In the linked discussions no working solution was given, so this is

why I open a new topic.

In my application, I have a NRF52832 development kit which should receive periodic packets from a custom board (later there will be n custom board, n = 5 more or less).

The DK is programmed with the ESB protocol in PRX mode, while the custom boards are programmed with the S132 and the timeslot API with ESB protocol in PTX mode.

Once a second, the custom board should transmit a message to the DK using the timeslot API (thus, the ESB protocol).

The problem I have is that when the custom board is advertising OR connected to a smartphone, all works perfectly fine: I receive all the data both on the smartphone and the DK with

the expected timings. When the custom board is disconnected AND/OR not advertising, then I receive on the DK only 1 packet every 10 seconds. For the record, I am on SDK 15.0.0.

If I do not start advertising, all my code (I have some periodical sensors sampling) runs perfectly fine and all the timings are well respected. The only issue is with the ESB transmissions, 

which are performed only once every 10 seconds.

From the look of it, it seems a configuration problem somewhere, but I was not able to find until now a solution. 

Can someone help me with this?

Thanks a lot!

Lorenzo

  • Hi,

     

    Is there any logic in your application that enters system off mode?

    Could you share a bit of code regarding the logic of the timeslot, and the handling in the application?

    When you enter debug mode, do you observe any unwanted/unexpected behavior?

     

    Kind regards,

    Håkon

  • Hi,

    thanks for your answer.

    Concerning the timeslot library, it was almost entirely taken from one of Nordic's examples in the github.

    Here it is

    #include "esb_timeslot.h"
    
    #include <stdint.h>
    #include <stdbool.h>
    #include "nrf.h"
    #include "app_error.h"
    #include "nrf_gpio.h"
    #include "nrf_sdh.h"
    #include "boards.h"
    #include "sdk_common.h"
    #include "app_util_platform.h"
    #include "fifo.h"
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #define TIMESLOT_BEGIN_IRQn        LPCOMP_IRQn
    #define TIMESLOT_BEGIN_IRQHandler  LPCOMP_IRQHandler
    #define TIMESLOT_BEGIN_IRQPriority 1
    #define TIMESLOT_END_IRQn          QDEC_IRQn
    #define TIMESLOT_END_IRQHandler    QDEC_IRQHandler
    #define TIMESLOT_END_IRQPriority   1
    #define ESB_RX_HANDLE_IRQn        WDT_IRQn
    #define ESB_RX_HANDLE_IRQHandler  WDT_IRQHandler
    #define ESB_RX_HANDLE_IRQPriority 3
    //Maximum attempt before discarding the packet (the number of trial = MAX_TX_ATTEMPTS x retransmit_count, if timeslot is large enough)
    #define MAX_TX_ATTEMPTS 10
    #define TS_LEN_US                          		(5000UL)
    #define TX_LEN_EXTENSION_US                 	(5000UL)
    #define TS_SAFETY_MARGIN_US                  	(700UL)    /**< The timeslot activity should be finished with this much to spare. */
    #define TS_EXTEND_MARGIN_US                     (2000UL)
    
    static volatile enum
    {
        STATE_IDLE, /* Default state */
        STATE_RX,   /* Waiting for packets */
        STATE_TX    /* Trying to transmit packet */
    } m_state = STATE_IDLE;
    
    // Variables for timeslot API
    static nrf_radio_request_t m_timeslot_request;
    
    static nrf_esb_config_t nrf_esb_config;
    static esb_data_handler_t m_evt_handler = 0;
    static fifo_t m_transmit_fifo;
    
    static nrf_radio_signal_callback_return_param_t signal_callback_return_param;
    static uint32_t         m_total_timeslot_length = 0;
    static uint32_t         m_tx_attempts = 0; 
    void RADIO_IRQHandler(void);
    
    
    /** Address. */
    static const uint8_t base_addr_0[4] = {0xE7, 0xE7, 0xE7, 0xE7};     /**< Base address part #0. */
    static const uint8_t base_addr_1[4] = {0xC2, 0xC2, 0xC2, 0xC2};     /**< Base address part #1. */
    static const uint8_t addr_prefix[8] = {0xE7, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8 };    /**< Address prefix. */
    
    
    /**@brief Request next timeslot event in earliest configuration
     */
    uint32_t request_next_event_earliest(void)
    {
        m_timeslot_request.request_type                = NRF_RADIO_REQ_TYPE_EARLIEST;
        m_timeslot_request.params.earliest.hfclk       = NRF_RADIO_HFCLK_CFG_XTAL_GUARANTEED;
        m_timeslot_request.params.earliest.priority    = NRF_RADIO_PRIORITY_HIGH;
        m_timeslot_request.params.earliest.length_us   = TS_LEN_US;
        m_timeslot_request.params.earliest.timeout_us  = 1000000;
        return sd_radio_request(&m_timeslot_request);
    }
    
    
    
    /**@brief Configure next timeslot event in earliest configuration
     */
    void configure_next_event_earliest(void)
    {
        m_timeslot_request.request_type                = NRF_RADIO_REQ_TYPE_EARLIEST;
        m_timeslot_request.params.earliest.hfclk       = NRF_RADIO_HFCLK_CFG_XTAL_GUARANTEED;
        m_timeslot_request.params.earliest.priority    = NRF_RADIO_PRIORITY_HIGH;
        m_timeslot_request.params.earliest.length_us   = TS_LEN_US;
        m_timeslot_request.params.earliest.timeout_us  = 1000000;
    }
    
    
    /**@brief Configure next timeslot event in normal configuration
     */
    void configure_next_event_normal(void)
    {
        m_timeslot_request.request_type               = NRF_RADIO_REQ_TYPE_NORMAL;
        m_timeslot_request.params.normal.hfclk        = NRF_RADIO_HFCLK_CFG_XTAL_GUARANTEED;
        m_timeslot_request.params.normal.priority     = NRF_RADIO_PRIORITY_HIGH;
        m_timeslot_request.params.normal.length_us    = TS_LEN_US;
        m_timeslot_request.params.normal.distance_us  = 100000;
    }
    
    
    /**@brief Timeslot signal handler
     */
    void nrf_evt_signal_handler(uint32_t evt_id)
    {
        uint32_t err_code;
    
        switch (evt_id)
        {
            case NRF_EVT_RADIO_SIGNAL_CALLBACK_INVALID_RETURN:
                //No implementation needed
                break;
            case NRF_EVT_RADIO_SESSION_IDLE:
                err_code = sd_radio_session_close();
                APP_ERROR_CHECK(err_code);
                break;
            case NRF_EVT_RADIO_SESSION_CLOSED:
                //No implementation needed, session ended
                break;
            case NRF_EVT_RADIO_BLOCKED:
                //Fall through
            case NRF_EVT_RADIO_CANCELED:
    		{
                err_code = request_next_event_earliest();
                APP_ERROR_CHECK(err_code);
                break;
    		}
    		default:
                break;					
        }
    }
    
    
    /**@brief Timeslot event handler
     */
    nrf_radio_signal_callback_return_param_t * timeslot_callback(uint8_t signal_type)
    {
        switch(signal_type)
        {
            case NRF_RADIO_CALLBACK_SIGNAL_TYPE_START:
    	
            	NRF_LOG_INFO(" NRF_RADIO_CALLBACK_SIGNAL_TYPE_START\r\n");
                //Start of the timeslot - set up timer interrupt
                signal_callback_return_param.params.request.p_next = NULL;
                signal_callback_return_param.callback_action = NRF_RADIO_SIGNAL_CALLBACK_ACTION_NONE;
    
                NRF_TIMER0->TASKS_STOP          = 1;
                NRF_TIMER0->TASKS_CLEAR         = 1;
                NRF_TIMER0->MODE                = (TIMER_MODE_MODE_Timer << TIMER_MODE_MODE_Pos);
                NRF_TIMER0->EVENTS_COMPARE[0]   = 0;
                NRF_TIMER0->EVENTS_COMPARE[1]   = 0;
                NRF_TIMER0->INTENSET 		    = TIMER_INTENSET_COMPARE0_Msk | TIMER_INTENSET_COMPARE1_Msk ;
                NRF_TIMER0->CC[0] 				= TS_LEN_US - TS_SAFETY_MARGIN_US;
    			NRF_TIMER0->CC[1] 				= (TS_LEN_US - TS_EXTEND_MARGIN_US);
                NRF_TIMER0->BITMODE             = (TIMER_BITMODE_BITMODE_24Bit << TIMER_BITMODE_BITMODE_Pos);				
    			NRF_TIMER0->TASKS_START         = 1;
    			NRF_RADIO->POWER                = (RADIO_POWER_POWER_Enabled << RADIO_POWER_POWER_Pos);
    				
    				
                NVIC_EnableIRQ(TIMER0_IRQn); 
                NVIC_SetPendingIRQ(TIMESLOT_BEGIN_IRQn);
    				
                break;
    
            case NRF_RADIO_CALLBACK_SIGNAL_TYPE_RADIO:  //2
    
                signal_callback_return_param.params.request.p_next = NULL;
                signal_callback_return_param.callback_action = NRF_RADIO_SIGNAL_CALLBACK_ACTION_NONE;
    
                ESB_TIMESLOT_DEBUG_PIN_SET(ESB_TIMESLOT_DBG_PIN_RADIO_IRQHANDLER);
                RADIO_IRQHandler();
                ESB_TIMESLOT_DEBUG_PIN_CLEAR(ESB_TIMESLOT_DBG_PIN_RADIO_IRQHANDLER);
    
                break;
    
            case NRF_RADIO_CALLBACK_SIGNAL_TYPE_TIMER0: //1
    					
                NRF_LOG_INFO(" NRF_RADIO_CALLBACK_SIGNAL_TYPE_TIMER0\r\n");
                if (NRF_TIMER0->EVENTS_COMPARE[0] &&
                     (NRF_TIMER0->INTENSET & (TIMER_INTENSET_COMPARE0_Enabled << TIMER_INTENCLR_COMPARE0_Pos)))
                {
                    NRF_TIMER0->TASKS_STOP        = 1;
                    NRF_TIMER0->EVENTS_COMPARE[0] = 0;
    
                    /* This is the "timeslot is about to end" timeout. */
                    if (!nrf_esb_is_idle())
                    {
                        NRF_RADIO->INTENCLR      = 0xFFFFFFFF;
                        NRF_RADIO->TASKS_DISABLE = 1;
                    }
    
                    /* Schedule next timeslot. */
                    configure_next_event_earliest();
                    signal_callback_return_param.params.request.p_next = &m_timeslot_request;
                    signal_callback_return_param.callback_action       = NRF_RADIO_SIGNAL_CALLBACK_ACTION_REQUEST_AND_END;
                }
    
                if (NRF_TIMER0->EVENTS_COMPARE[1] &&
                     (NRF_TIMER0->INTENSET & (TIMER_INTENSET_COMPARE1_Enabled << TIMER_INTENCLR_COMPARE1_Pos)))
                {
                    NRF_TIMER0->EVENTS_COMPARE[1] = 0;
                    if (m_total_timeslot_length < (128000000UL - 1UL - TX_LEN_EXTENSION_US))
                    {
                            // Request timeslot extension if total length does not exceed 128 seconds
                        signal_callback_return_param.params.extend.length_us = TX_LEN_EXTENSION_US;
                        signal_callback_return_param.callback_action = NRF_RADIO_SIGNAL_CALLBACK_ACTION_EXTEND;
                    }
                    else
                    {
                        // Return with no action request
                        signal_callback_return_param.params.request.p_next = NULL;
                        signal_callback_return_param.callback_action = NRF_RADIO_SIGNAL_CALLBACK_ACTION_NONE;
                    }
                }
                break;
            case NRF_RADIO_CALLBACK_SIGNAL_TYPE_EXTEND_SUCCEEDED:   //4
            	// NRF_LOG("  NRF_RADIO_CALLBACK_SIGNAL_TYPE_EXTEND_SUCCEEDED\r\n");
                NRF_TIMER0->TASKS_STOP          = 1;
                NRF_TIMER0->EVENTS_COMPARE[0]   = 0;
                NRF_TIMER0->EVENTS_COMPARE[1]   = 0;
                NRF_TIMER0->CC[0]               += (TX_LEN_EXTENSION_US - 25);
                NRF_TIMER0->CC[1]               += (TX_LEN_EXTENSION_US - 25);
                NRF_TIMER0->TASKS_START         = 1;
                m_total_timeslot_length += TX_LEN_EXTENSION_US;
                NVIC_SetPendingIRQ(TIMESLOT_BEGIN_IRQn);
                break;
            
            case NRF_RADIO_CALLBACK_SIGNAL_TYPE_EXTEND_FAILED:
                //NRF_LOG(" NRF_RADIO_CALLBACK_SIGNAL_TYPE_EXTEND_FAILED\r\n");
                //Try scheduling a new timeslot
                // Disabling ESB is done in a lower interrupt priority
                NVIC_SetPendingIRQ(TIMESLOT_END_IRQn);
    
                signal_callback_return_param.params.request.p_next = NULL;
                signal_callback_return_param.callback_action = NRF_RADIO_SIGNAL_CALLBACK_ACTION_NONE;
                break;
            default:
    			//No implementation needed
    			break;
        }
        return (&signal_callback_return_param);
    }
    
    //!
    //! @brief Function for initializing the timeslot API.
    //!
    //!
    uint32_t timeslot_sd_start(void)
    {
        uint32_t err_code;
    
        err_code = sd_radio_session_open(timeslot_callback);
        if (err_code != NRF_SUCCESS)
        {
           NRF_LOG_INFO("Err: %d\n", err_code);
            return err_code;
        }
        err_code = request_next_event_earliest();
                NRF_LOG_INFO("Err: %d\n", err_code);
    
        if (err_code != NRF_SUCCESS)
        {
            (void)sd_radio_session_close();
            return err_code;
        }
        return NRF_SUCCESS;
    }
    
    /**@brief IRQHandler used for execution context management. 
      *        Any available handler can be used as we're not using the associated hardware.
      *        This handler is used to stop and disable UESB
      */
    void TIMESLOT_END_IRQHandler(void)
    {
        uint32_t err_code;
    
        ESB_TIMESLOT_DEBUG_PIN_SET(ESB_TIMESLOT_DBG_PIN_DISABLE);
    	//NRF_LOG("TIMESLOT_END_IRQHandler\r\n");
        // Timeslot is about to end: stop UESB
        if (m_state == STATE_RX)
        {  
    		err_code= nrf_esb_stop_rx();
        }
    	err_code= nrf_esb_flush_tx();
    //	APP_ERROR_CHECK(err_code);
    	err_code= nrf_esb_flush_rx();
    //	APP_ERROR_CHECK(err_code);
        err_code= nrf_esb_disable();
    //    APP_ERROR_CHECK(err_code);
        m_total_timeslot_length = 0;
        m_state = STATE_IDLE;
    
    
        ESB_TIMESLOT_DEBUG_PIN_CLEAR(ESB_TIMESLOT_DBG_PIN_DISABLE);
        ESB_TIMESLOT_DEBUG_PIN_CLEAR(ESB_TIMESLOT_DBG_PIN_RADIO_TIMESLOT);
    }
    
    /**@brief IRQHandler used for execution context management. 
     *        Any available handler can be used as we're not using the associated hardware.
     *        This handler is used to initiate ESB RX/TX
     */
    void TIMESLOT_BEGIN_IRQHandler(void)
    {
        uint32_t err_code;
    	nrf_esb_payload_t     tx_payload ;
    	uint32_t       tx_payload_len;
        bool can_continue = true;
    	//NRF_LOG("TIMESLOT_BEGIN_IRQHandler\r\n");
    
    	ESB_TIMESLOT_DEBUG_PIN_SET(ESB_TIMESLOT_DBG_PIN_RADIO_TIMESLOT);
    
    	if (m_state == STATE_IDLE)
        {
    			
    		err_code = nrf_esb_init(&nrf_esb_config);
            if (err_code != NRF_SUCCESS)
            {
                can_continue = false;
            }
    		err_code = nrf_esb_set_base_address_0(base_addr_0);
            if (err_code != NRF_SUCCESS)
            {
                can_continue = false;
            }
    		err_code = nrf_esb_set_base_address_1(base_addr_1);
            if (err_code != NRF_SUCCESS)
            {
                can_continue = false;
            }		err_code = nrf_esb_set_prefixes(addr_prefix, 8);
    
            if (err_code != NRF_SUCCESS)
            {
                can_continue = false;
            }    
        }
        if (can_continue)
        {
            CRITICAL_REGION_ENTER();
            if (m_transmit_fifo.free_items < sizeof(m_transmit_fifo.buf) && m_state != STATE_TX)
            {				
                // There are packets in the FIFO: Start transmitting
                tx_payload_len  = sizeof(tx_payload);
                // Copy packet from FIFO. Packet isn't removed until transmissions succeeds or max retries has been exceeded
                if (m_tx_attempts < MAX_TX_ATTEMPTS)
                {        
                    fifo_peek_pkt(&m_transmit_fifo, (uint8_t *) &tx_payload, &tx_payload_len);
                    APP_ERROR_CHECK_BOOL(tx_payload_len == sizeof(tx_payload));
                }
                else
                {	
                    //max attempts reached, remove packet
                    NRF_LOG_ERROR("FAILED TO SEND, NO ACK\r\n");
                    fifo_get_pkt(&m_transmit_fifo, (uint8_t *) &tx_payload, &tx_payload_len);
                    APP_ERROR_CHECK_BOOL(tx_payload_len == sizeof(tx_payload));
                
                    m_tx_attempts = 0;
                }
            
                if (m_state == STATE_RX)
                {
                    nrf_esb_stop_rx(); 
                }
         
                err_code = nrf_esb_write_payload(&tx_payload);
                APP_ERROR_CHECK(err_code);
            
                m_state = STATE_TX;
            }
            else
            {
                // No packets in the FIFO: start reception
                err_code = nrf_esb_start_rx();
                APP_ERROR_CHECK(err_code);
                m_state = STATE_RX;
    
            }
            CRITICAL_REGION_EXIT();
        }
    }
    
    uint32_t esb_timeslot_send_str(uint8_t * p_str, uint32_t length)
    {
    	static nrf_esb_payload_t tx_payload;
        bool success;
        memset(&tx_payload, 0, sizeof(tx_payload));
        memcpy(tx_payload.data, p_str, length);
        tx_payload.length = length;
        tx_payload.pipe = 0;
        CRITICAL_REGION_ENTER();
        success = fifo_put_pkt(&m_transmit_fifo, (uint8_t *)&tx_payload, sizeof(tx_payload));
        CRITICAL_REGION_EXIT();
        return success ? NRF_SUCCESS : NRF_ERROR_NO_MEM;
    }
    
    uint32_t esb_timeslot_send_buffer(uint8_t *dataToSend, uint32_t length, uint32_t hw_addr)
    {
        static nrf_esb_payload_t tx_payload;
        bool success;
        memset(&tx_payload, 0, sizeof(tx_payload));
        memcpy(tx_payload.data, dataToSend, length);
        tx_payload.data[19] = (hw_addr >> 24);
        tx_payload.data[20] = (hw_addr >> 16);
        tx_payload.data[21] = (hw_addr >> 8);
        tx_payload.data[22] = hw_addr;
        tx_payload.length = length + 4;
        tx_payload.pipe = 0;
        CRITICAL_REGION_ENTER();
        success = fifo_put_pkt(&m_transmit_fifo, (uint8_t *)&tx_payload, sizeof(tx_payload));
        CRITICAL_REGION_EXIT();
        return success ? NRF_SUCCESS : NRF_ERROR_NO_MEM;
    
    
    }
    
    void nrf_esb_event_handler(nrf_esb_evt_t const * p_event)
    {
    	//NRF_LOG("NRF ESB EVENT HANDLERr\r\n");
    	if(p_event->evt_id == NRF_ESB_EVENT_TX_FAILED)
        { 
    		nrf_esb_flush_tx();
            // Data reception is handled in a lower priority interrupt
            m_tx_attempts += 1;
            m_state = STATE_RX;
    			
        }
    	if (p_event->evt_id == NRF_ESB_EVENT_TX_SUCCESS)
        {		
            nrf_esb_payload_t payload;
            uint32_t       payload_len;
            
            // Successful transmission. Can now remove packet from our FIFO
            payload_len = sizeof(payload);
    
            fifo_get_pkt(&m_transmit_fifo, (uint8_t *) &payload, &payload_len);
            APP_ERROR_CHECK_BOOL(payload_len == sizeof(payload));
            
            m_tx_attempts = 0;
        }
    		
        if(p_event->evt_id & NRF_ESB_EVENT_RX_RECEIVED)
        {
            // Data reception is handled in a lower priority interrupt
            NVIC_SetPendingIRQ(ESB_RX_HANDLE_IRQn);
        }
    }
    
    uint32_t esb_init(esb_data_handler_t evt_handler)
    {
    
        nrf_esb_config_t tmp_config  = NRF_ESB_DEFAULT_CONFIG;
    		
    		
    	m_evt_handler = evt_handler;
        memcpy(&nrf_esb_config, &tmp_config, sizeof(nrf_esb_config_t));
        nrf_esb_config.payload_length     = 32;
        nrf_esb_config.protocol           = NRF_ESB_PROTOCOL_ESB_DPL;
        nrf_esb_config.bitrate            = NRF_ESB_BITRATE_2MBPS;
        nrf_esb_config.mode               = NRF_ESB_MODE_PTX;
        nrf_esb_config.event_handler      = nrf_esb_event_handler;
        nrf_esb_config.selective_auto_ack = false;
    	nrf_esb_config.radio_irq_priority = 0;
        fifo_init(&m_transmit_fifo);
    
        // Using three avilable interrupt handlers for interrupt level management
        // These can be any available IRQ as we're not using any of the hardware,
        // simply triggering them through software
        NVIC_ClearPendingIRQ(TIMESLOT_END_IRQn);
        NVIC_SetPriority(TIMESLOT_END_IRQn, 1);
        NVIC_EnableIRQ(TIMESLOT_END_IRQn);
        
        NVIC_ClearPendingIRQ(TIMESLOT_BEGIN_IRQn);
        NVIC_SetPriority(TIMESLOT_BEGIN_IRQn, 1);
        NVIC_EnableIRQ(TIMESLOT_BEGIN_IRQn);
        
        NVIC_ClearPendingIRQ(ESB_RX_HANDLE_IRQn);
        NVIC_SetPriority(ESB_RX_HANDLE_IRQn, 1);
        NVIC_EnableIRQ(ESB_RX_HANDLE_IRQn);
    
        return NRF_SUCCESS;
    }
    
    
    void ESB_RX_HANDLE_IRQHandler(void)
    {
        nrf_esb_payload_t rx_payload;
        uint32_t err_code;
    		
    	//NRF_LOG("UESB_RX_HANDLE_IRQHandler \r\n");
        // Get packet from UESB buffer
        err_code = nrf_esb_read_rx_payload(&rx_payload);
        APP_ERROR_CHECK(err_code);
    	
        // Give packet to main application 
        // app_scheduler can be used instead to send the event in main context
        m_evt_handler(rx_payload.data, rx_payload.length);
    }
    
    

    As for the main, I simply have a timer which once a second invokes the esb send function as below

             err_code = esb_timeslot_send_buffer(to_send, 19, hw_addr);       
    

    Actually this function simply puts the data in the tx_fifo, and the fifo is emptied when a timeslot is available.

    Of course, the esb_init function is properly called in the initialization phase of my main class.

    When in debug mode, I see that the event 

    nrf_radio_signal_callback_return_param_t * timeslot_callback(uint8_t signal_type)
    {
        switch(signal_type)
        {
            case NRF_RADIO_CALLBACK_SIGNAL_TYPE_START:
    	
            	NRF_LOG_INFO(" NRF_RADIO_CALLBACK_SIGNAL_TYPE_START\r\n");

    is correctly called once per second when advertising.

    When no advertising, the event is called once every 10 seconds as I said in the initial post. I don't see any strange behavior, as I said also when not advertising all the operations happens normally. The enqueueing in the ESB fifo works as well, but after some time I got a "fifo full" error message, because obviously the fifo is not emptied quick enough.

    In the main while cycle, I had inface the idle_state_handle() function call, but even if I try to disable it I still got the same behaviour.

    I am honestly out of ideas....I definitely need a solution to this problem because in the envisaged application I need to have x boards active at the same time, sending their packets to the ESB board and they MUST NOT advertise.

    Hope you can help, and thanks in advance for the support!

  • Given the behavior you're seeing, it sounds like the timeslot is being terminated (or not extended) for some reason. Does the "TIMESLOT_END_IRQHandler" ever get called? Is there anything in your application that is linked to a 10 sec timeout? How does the application handle the timeslot?

    And you are 100 % certain that there's nothing in the application that calls system off or similar after a BLE connection/advertisement is terminated (look for the sleep_mode_enter() function)?

    If you are uncertain how to debug this, the dynamic current consumption of the device should give an indication on what happens, as the radio peaks should be visible there.

    What is your assert-behavior? The default is to do a system reset, and you can enable blocking asserts by adding "DEBUG" to the preprocessor definitions.

     

    Kind regards,

    Håkon

  • Hello again, I'll summarize the answers below, but first I will decribe in steps my applications, so it will be more clear.

    1 - Power ON: NO ADVERTISING, the board measures sensors once per second, and it *should* transmit a 20-bytes log using esb with the timeslot api. (this does not work, since I have one timeslot every 10 seconds, but the sensor readings and the esb preparation of packet in the tx fifo works fine)

    2 - when a smartphone with NFC comes close to the board NFC antenna, the board starts advertising and it keeps the same behavior, but the log is sent also via bluetooth once the smartphone is connected (this works fine with both BLE and ESB logs transmitted and received)

    3 - when the smartphone disconnects from the board, we whould go back to point 1 (not working, see point 1)

    As for your questions

    1 - yes, the END_IRQHandler is called regularly, both after a NRF_RADIO_CALLBACK_SIGNAL_TYPE_START and after a NRF_RADIO_CALLBACK_SIGNAL_TYPE_RADIO

    2 - Nothing related to a 10 seconds timeout. Again, the application is not blocked, I simply do not have a timeslot. The application does not handle the timeslot; the application only puts packets in the fifo, and when the timeslot is assigned (Timeslot_BEGIN_IRQHandler) the fifo is checked and the packet is transmitted, if any.

    3 - sleep_mode_enter or system_off are never called, the application runs fine with the exception of the timeslots.

    4 - I also do a system reset, but this does not happen (I can use the segger debug or log printouts, and I see that the application runs correctly).

    If it may help, when not advertising, in the function "timeslot_callback" I see a NRF_RADIO_CALLBACK_SIGNAL_TYPE_START debug log once every 10 seconds, while for the rest of the time, I see a NRF_RADIO_CALLBACK_SIGNAL_TYPE_RADIO. 

    Is it possible that the softdevice, if it is not performing an advertising or some other operation, falls back to a very low timeslot allocation to save energy? Or simply, since there is no radio activity, the timeslot cannot allocate any slot?

    For the moment I used a workaround, in that I advertise a non-connectable beacon and I change advertising mode in case of NFC activity. This works for the purpose of my application, but in case of many devices, it could create unnecessary traffic, which is not so good for us....

    Let me know if you have other suggestions, thanks for your help!

  • lbe said:
    yes, the END_IRQHandler is called regularly, both after a NRF_RADIO_CALLBACK_SIGNAL_TYPE_START and after a NRF_RADIO_CALLBACK_SIGNAL_TYPE_RADIO

     The only way you can get a _END_IRQHandler called, based on the sources that you have attached here, is if the timeslot fails to extend. Could you see if this is the case when the softdevice is "inactive"?

Related