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

Timeslot events getting blocked

Hi 
I'm trying to integrate the iBeacon and Eddystone protocol together. For this I'm using the timeslot to advertise the packets simultaneously. I have successfully integrated the ibeacon and eddystone together and it is working fine.

But the issue comes when i try to update the advertising interval the radio events are getting blocked. Always it advertises for few seconds and then error pops up. While integrating i have fixed a value for the advertising interval and successfully integrated it but when i change the values of advertising interval the issue arises.

The err_code says ERROR 17 [NRF_ERROR_BUSY]

I do have some questions reg the time-slot parameters

1. while requesting the next event or the earliest does the timeout_us event and length_us have any dependencies on advertising interval? Do we need to change those as per adv interval?

2. using the NRF_LOG_INFO has been an issue with the timeslot. ERROR 17 [NRF_ERROR_BUSY] .

I have attached my code, could you please let me know if i'm doing anything wrong

thanks

 

 

 

 




static enum packet_t packet = IBEACON;

int pdu_count = 1;

uint32_t m_request_earliest_beacon(enum NRF_RADIO_PRIORITY priority)
{
    m_adv.timeslot_request.request_type                = NRF_RADIO_REQ_TYPE_EARLIEST;
    m_adv.timeslot_request.params.earliest.hfclk       = NRF_RADIO_HFCLK_CFG_NO_GUARANTEE;
    m_adv.timeslot_request.params.earliest.priority    = priority;
    m_adv.timeslot_request.params.earliest.length_us   = SLOT_LENGTH;
    m_adv.timeslot_request.params.earliest.timeout_us  = 1000UL;
    return sd_radio_request(&m_adv.timeslot_request);
}

nrf_radio_request_t * m_configure_next_event_beacon(uint32_t interval_us)
{
    m_adv.timeslot_request.request_type              = NRF_RADIO_REQ_TYPE_NORMAL;
    m_adv.timeslot_request.params.normal.hfclk       = NRF_RADIO_HFCLK_CFG_NO_GUARANTEE;
    m_adv.timeslot_request.params.normal.priority    = NRF_RADIO_PRIORITY_HIGH;
    m_adv.timeslot_request.params.normal.distance_us = interval_us * 1000; //to ms
    m_adv.timeslot_request.params.normal.length_us   = SLOT_LENGTH;
    return &m_adv.timeslot_request;
}

uint32_t m_request_normal(void)
{
    m_adv.timeslot_request.request_type                = NRF_RADIO_REQ_TYPE_NORMAL;
    m_adv.timeslot_request.params.normal.hfclk         = NRF_RADIO_HFCLK_CFG_XTAL_GUARANTEED;
    m_adv.timeslot_request.params.normal.priority      = NRF_RADIO_PRIORITY_NORMAL;
    m_adv.timeslot_request.params.normal.distance_us   = _ibeacon_ts.adv_interval * 1000 * 2;
    m_adv.timeslot_request.params.normal.length_us     = SLOT_LENGTH;
    return sd_radio_request(&m_adv.timeslot_request);
}


/* common config */

static void m_configure_radio()
{
    NRF_RADIO->POWER        = 1;
    NRF_RADIO->PCNF0        =   (((1UL) << RADIO_PCNF0_S0LEN_Pos                               ) & RADIO_PCNF0_S0LEN_Msk)
                             | (((2UL) << RADIO_PCNF0_S1LEN_Pos                               ) & RADIO_PCNF0_S1LEN_Msk)
                             | (((6UL) << RADIO_PCNF0_LFLEN_Pos                               ) & RADIO_PCNF0_LFLEN_Msk);
    NRF_RADIO->PCNF1        =   (((RADIO_PCNF1_ENDIAN_Little)     << RADIO_PCNF1_ENDIAN_Pos    ) & RADIO_PCNF1_ENDIAN_Msk)
	                     | (((3UL)                           << RADIO_PCNF1_BALEN_Pos     ) & RADIO_PCNF1_BALEN_Msk)
	                     | (((0UL)                           << RADIO_PCNF1_STATLEN_Pos   ) & RADIO_PCNF1_STATLEN_Msk)
	                     | ((((uint32_t) 37)                 << RADIO_PCNF1_MAXLEN_Pos    ) & RADIO_PCNF1_MAXLEN_Msk)
	                     | ((RADIO_PCNF1_WHITEEN_Enabled     << RADIO_PCNF1_WHITEEN_Pos   ) & RADIO_PCNF1_WHITEEN_Msk);
    NRF_RADIO->CRCCNF       =   (((RADIO_CRCCNF_SKIPADDR_Skip)    << RADIO_CRCCNF_SKIPADDR_Pos ) & RADIO_CRCCNF_SKIPADDR_Msk)
	                              | (((RADIO_CRCCNF_LEN_Three)        << RADIO_CRCCNF_LEN_Pos      ) & RADIO_CRCCNF_LEN_Msk);
    NRF_RADIO->CRCPOLY      = 0x0000065b;
    NRF_RADIO->RXADDRESSES  = ((RADIO_RXADDRESSES_ADDR0_Enabled)  << RADIO_RXADDRESSES_ADDR0_Pos);
    NRF_RADIO->SHORTS       = ((1 << RADIO_SHORTS_READY_START_Pos) | (1 << RADIO_SHORTS_END_DISABLE_Pos));
    NRF_RADIO->MODE         = ((RADIO_MODE_MODE_Ble_1Mbit)        << RADIO_MODE_MODE_Pos       ) & RADIO_MODE_MODE_Msk;
    NRF_RADIO->TIFS         = 150;
    NRF_RADIO->INTENSET     = (1 << RADIO_INTENSET_DISABLED_Pos);
    NRF_RADIO->PREFIX0      = 0x0000008e; //access_addr[3]
    NRF_RADIO->BASE0        = 0x89bed600; //access_addr[0:3]
    NRF_RADIO->CRCINIT      = 0x00555555;

    NVIC_DisableIRQ(RADIO_IRQn);
    NVIC_EnableIRQ(RADIO_IRQn);
}

static void periph_radio_evts_clear(void)
{
    NRF_RADIO->EVENTS_ADDRESS 	= 0;
    NRF_RADIO->EVENTS_BCMATCH 	= 0;
    NRF_RADIO->EVENTS_DEVMATCH 	= 0;
    NRF_RADIO->EVENTS_DEVMISS 	= 0;
    NRF_RADIO->EVENTS_DISABLED 	= 0;
    NRF_RADIO->EVENTS_END 		= 0;
    NRF_RADIO->EVENTS_PAYLOAD 	= 0;
    NRF_RADIO->EVENTS_READY 	= 0;
    NRF_RADIO->EVENTS_RSSIEND 	= 0;
}
static void m_handle_start(uint8_t ch1,uint8_t ch2)
{
    // Configure TX_EN on TIMER EVENT_0
    NRF_PPI->CH[ch1].TEP    = (uint32_t)(&NRF_RADIO->TASKS_TXEN);
    NRF_PPI->CH[ch1].EEP    = (uint32_t)(&NRF_TIMER0->EVENTS_COMPARE[ch2]);
    NRF_PPI->CHENSET      = (1 << ch1);

    // Configure and initiate radio
    m_configure_radio();
    periph_radio_evts_clear();
    NRF_RADIO->TASKS_DISABLE = 1;


}

static void m_set_adv_ch(uint32_t channel)
{
    if (channel == ADV_CHANNEL_37)
    {
        NRF_RADIO->FREQUENCY    = FREQ_ADV_CHANNEL_37;
        NRF_RADIO->DATAWHITEIV  = ADV_CHANNEL_37;
    }
    if (channel == ADV_CHANNEL_38)
    {
        NRF_RADIO->FREQUENCY    = FREQ_ADV_CHANNEL_38;
        NRF_RADIO->DATAWHITEIV  = ADV_CHANNEL_38;
    }
   if (channel == ADV_CHANNEL_39)
    {
        NRF_RADIO->FREQUENCY    = FREQ_ADV_CHANNEL_39;
        NRF_RADIO->DATAWHITEIV  = ADV_CHANNEL_39;
    }
}


static void m_handle_radio_disabled(enum mode_t mode, uint8_t ch)
{
    switch (mode)
    {
        case ADV_RX_CH37:
            m_set_adv_ch(ADV_CHANNEL_37);
            NRF_RADIO->TASKS_TXEN = 1;
            break;
        case ADV_RX_CH38:
            m_set_adv_ch(ADV_CHANNEL_38);
            NRF_TIMER0->TASKS_CLEAR = 1;
            NRF_TIMER0->CC[ch]      = 400;
            break;
        case ADV_RX_CH39:
            m_set_adv_ch(ADV_CHANNEL_39);
            NRF_TIMER0->TASKS_CLEAR = 1;
            NRF_TIMER0->CC[ch]      = 400;

            break;
        default:
            break;
    }
}
void get_eddystone_packet()
{
NRF_RADIO->PACKETPTR = (uint32_t) m_get_adv_packet_es_uid();
               }
}

static nrf_radio_signal_callback_return_param_t * m_timeslot_callback(uint8_t signal_type)
{
   static nrf_radio_signal_callback_return_param_t signal_callback_return_param;
   static enum mode_t mode;

   signal_callback_return_param.params.request.p_next  = NULL;
   signal_callback_return_param.callback_action        = NRF_RADIO_SIGNAL_CALLBACK_ACTION_NONE;

   switch (signal_type) 
   {
    case NRF_RADIO_CALLBACK_SIGNAL_TYPE_START:
         
         NRF_LOG_INFO("i'am in SIGNAL_TYPE_START");
	 switch (packet) 
         {
          case IBEACON:
	       m_handle_start(7,0);
	       break;
	  case EDDYSTONE :
               m_handle_start(8,1);
               break;
	 }
	 mode = ADV_INIT;
	 mode++;
    break;

    case NRF_RADIO_CALLBACK_SIGNAL_TYPE_RADIO:
      
      switch (packet) 
      {
	case IBEACON:
          
          if (NRF_RADIO->EVENTS_DISABLED == 1) 
          {
            NRF_RADIO->EVENTS_DISABLED = 0;
            m_handle_radio_disabled(mode,0);
            mode++;
            
            NRF_RADIO->PACKETPTR = (uint32_t) m_get_adv_packet_ibeacon();
            
            if (mode == ADV_DONE)
            {
              NRF_LOG_INFO("i'am in ibeacon TYPE_RADIO");
              NRF_PPI->CHENCLR = (1 << 7);
              packet = EDDYSTONE;

              if (m_adv.is_running)
              {
		signal_callback_return_param.params.request.p_next = m_configure_next_event_beacon(_ibeacon_ts.adv_interval);
                signal_callback_return_param.callback_action = NRF_RADIO_SIGNAL_CALLBACK_ACTION_REQUEST_AND_END;
              } 
              else 
              {
                signal_callback_return_param.callback_action =NRF_RADIO_SIGNAL_CALLBACK_ACTION_END;
              }
            }
	}
	break;
        
        case EDDYSTONE:

                 if (NRF_RADIO->EVENTS_DISABLED == 1)
                 {
                    NRF_RADIO->EVENTS_DISABLED = 0;
                     m_handle_radio_disabled(mode,1);
                    mode++;
                    get_eddystone_packet();
                   
                    if (mode == ADV_DONE)
                    {
                      NRF_LOG_INFO("i'am in eddystone TYPE_RADIO \n");
                      NRF_PPI->CHENCLR = (1 << 8);

                      packet = IBEACON;
                      if (m_adv.is_running)
                      {
                        signal_callback_return_param.params.request.p_next = m_configure_next_event_beacon(_eddystone.adv_interval);
                        signal_callback_return_param.callback_action       = NRF_RADIO_SIGNAL_CALLBACK_ACTION_REQUEST_AND_END;
                        NRF_RADIO->INTENSET     = (0 << RADIO_INTENSET_DISABLED_Pos);
                      } 
                      else 
                      {
                        signal_callback_return_param.callback_action = NRF_RADIO_SIGNAL_CALLBACK_ACTION_END;
                      }
                    }
                 }        

                break;
      }
      break;

      default:
	if (_ibeacon_ts.error_handler != NULL) 
          {
            _ibeacon_ts.error_handler(NRF_ERROR_INVALID_STATE);
          }
          if (_eddystone.error_handler != NULL) 
          {
            _eddystone.error_handler(NRF_ERROR_INVALID_STATE);
          }
      break;

	}
	return (&signal_callback_return_param);
}

void app_beacon_sd_evt_signal_handler(uint32_t event)
{
    uint32_t err_code;
    NRF_LOG_INFO("app_beacon_on_sys_evt: %d\r\n", event);
    switch (event)
    {
	case NRF_EVT_RADIO_SESSION_IDLE:
		NRF_LOG_INFO("Radio IDLE");
		if (m_adv.is_running)
                {
                  err_code = sd_radio_session_close();
                  APP_ERROR_CHECK(err_code);
		  if ((err_code != NRF_SUCCESS) && (_ibeacon_ts.error_handler != NULL) && (_eddystone.error_handler != NULL))
                  {
                    _ibeacon_ts.error_handler(err_code);
                  } 
                  m_adv.is_running = false;
		}
		break;
	case NRF_EVT_RADIO_SESSION_CLOSED:
		NRF_LOG_INFO("Radio closed");
                if (m_adv.keep_running) 
                {
                  _beacon_advertising_start();
		}

		break;
	case NRF_EVT_RADIO_BLOCKED:
		NRF_LOG_INFO("Radio blocked");
		err_code = sd_radio_session_close();
                APP_ERROR_CHECK(err_code);

		uint32_t err_code = sd_radio_session_open(m_timeslot_callback);
		NRF_LOG_INFO("Timeslot session opened");
		if ((err_code != NRF_SUCCESS) && (_ibeacon_ts.error_handler != NULL) && (_eddystone.error_handler != NULL))
                {
                    _ibeacon_ts.error_handler(err_code);
                } 
		// TODO: A proper solution should try again in <block_count> * m_beacon.adv_interval
		err_code = m_request_earliest_beacon(NRF_RADIO_PRIORITY_HIGH);
		if ((err_code != NRF_SUCCESS) && (_ibeacon_ts.error_handler != NULL) && (_eddystone.error_handler != NULL))
                {
                    _ibeacon_ts.error_handler(err_code);
                } 
		break;

	case NRF_EVT_RADIO_CANCELED: // Fall through
		NRF_LOG_INFO("Timeslot CANCELED");
		 if (m_adv.keep_running)
                 {
                  // TODO: A proper solution should try again in <block_count> * m_beacon.adv_interval
                  // err_code = m_request_earliest(NRF_RADIO_PRIORITY_HIGH);
                  err_code = m_request_normal();
                  if ((err_code != NRF_SUCCESS) && (_ibeacon_ts.error_handler != NULL) && (_eddystone.error_handler != NULL))
                  {
                      _ibeacon_ts.error_handler(err_code);
                  } 
                 }
		break;
        default:
        	NRF_LOG_INFO("Radio default");
        break;
    }
}





void _beacon_advertising_start(void)
{
    m_adv.keep_running = true;
    m_adv.is_running   = true;

    uint32_t err_code = sd_radio_session_open(m_timeslot_callback);
    NRF_LOG_INFO("Timeslot session opened");
    if ((err_code != NRF_SUCCESS) && (_ibeacon_ts.error_handler != NULL) && (_eddystone.error_handler != NULL))
    {
        _ibeacon_ts.error_handler(err_code);
    }
    
    err_code = m_request_earliest_beacon(NRF_RADIO_PRIORITY_HIGH);
    NRF_LOG_INFO("Timeslot request earliest");
    if ((err_code != NRF_SUCCESS) && (_ibeacon_ts.error_handler != NULL) && (_eddystone.error_handler != NULL))
    {
        _ibeacon_ts.error_handler(err_code);
    } 
}



void _beacon_advertising_stop(void)
{
    m_adv.keep_running = false;
}

Parents
  • 1. while requesting the next event or the earliest does the timeout_us event and length_us have any dependencies on advertising interval? Do we need to change those as per adv interval?

    If you are using timeslots for advertising, then the length_us should be directly related to the advertising interval. That is the smaller the advertising interval of the other beacon, the less probable is it get length_us fit into the timeslot.  Can you for reference show me the numbers for advertising intervals and length_us and timeout_us to get a better picture? 

    Regarding the NRF_ERROR_BUSY, Which softdevice version are they using? Was any previous sessions closed using sd_radio_session_close and waiting for NRF_EVT_RADIO_SESSION_CLOSED before calling sd_radio_session_open

    I can clearly see that in NRF_EVT_RADIO_BLOCKED, you are closing the session and starting the new session immediately without waiting for NRF_EVT_RADIO_SESSION_CLOSED. You should change your code to start a new session after you get NRF_EVT_RADIO_SESSION_CLOSED since session_closed is an async operation.

Reply
  • 1. while requesting the next event or the earliest does the timeout_us event and length_us have any dependencies on advertising interval? Do we need to change those as per adv interval?

    If you are using timeslots for advertising, then the length_us should be directly related to the advertising interval. That is the smaller the advertising interval of the other beacon, the less probable is it get length_us fit into the timeslot.  Can you for reference show me the numbers for advertising intervals and length_us and timeout_us to get a better picture? 

    Regarding the NRF_ERROR_BUSY, Which softdevice version are they using? Was any previous sessions closed using sd_radio_session_close and waiting for NRF_EVT_RADIO_SESSION_CLOSED before calling sd_radio_session_open

    I can clearly see that in NRF_EVT_RADIO_BLOCKED, you are closing the session and starting the new session immediately without waiting for NRF_EVT_RADIO_SESSION_CLOSED. You should change your code to start a new session after you get NRF_EVT_RADIO_SESSION_CLOSED since session_closed is an async operation.

Children
Related