Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs

Concurrents connections (2 identicals centrals try to connect to the same peripheral at the same time)

Hello,

I have a project (using NUS) that comes in 2 parts:

  1. NRF52840 (peripheral) which generate advertising when they have information to transmit.
  2. PCA10059 USB dongles that constantly scan for the above peripherals

I encounter a problem when several USB dongles (with same firmware) receive advertising from a device...
In this case, sometimes the dongles synchronize perfectly and simultaneously try to communicate with the peripheral which launched its advertising.

Each dongle then generates a BLE_NUS_C_EVT_DISCONNECTED event with which I relaunch a scan_start, and so on a few times for ten seconds !

I tried to modify NRF_BLE_SCAN_SCAN_INTERVAL and NRF_BLE_SCAN_SUPERVISION_TIMEOUT like this (but with some small result) :

// <o> NRF_BLE_SCAN_SCAN_INTERVAL - Scanning interval. Determines the scan interval in units of 0.625 millisecond. 
#ifndef NRF_BLE_SCAN_SCAN_INTERVAL
#define NRF_BLE_SCAN_SCAN_INTERVAL 100
#endif

// <o> NRF_BLE_SCAN_SCAN_DURATION - Duration of a scanning session in units of 10 ms. Range: 0x0001 - 0xFFFF (10 ms to 10.9225 ms). If set to 0x0000, the scanning continues until it is explicitly disabled. 
#ifndef NRF_BLE_SCAN_SCAN_DURATION
#define NRF_BLE_SCAN_SCAN_DURATION 0
#endif

// <o> NRF_BLE_SCAN_SCAN_WINDOW - Scanning window. Determines the scanning window in units of 0.625 millisecond. 
#ifndef NRF_BLE_SCAN_SCAN_WINDOW
#define NRF_BLE_SCAN_SCAN_WINDOW 100
#endif

// <o> NRF_BLE_SCAN_MIN_CONNECTION_INTERVAL - Determines minimum connection interval in milliseconds. 
#ifndef NRF_BLE_SCAN_MIN_CONNECTION_INTERVAL
#define NRF_BLE_SCAN_MIN_CONNECTION_INTERVAL 7.5
#endif

// <o> NRF_BLE_SCAN_MAX_CONNECTION_INTERVAL - Determines maximum connection interval in milliseconds. 
#ifndef NRF_BLE_SCAN_MAX_CONNECTION_INTERVAL
#define NRF_BLE_SCAN_MAX_CONNECTION_INTERVAL 40
#endif

// <o> NRF_BLE_SCAN_SLAVE_LATENCY - Determines the slave latency in counts of connection events. 
#ifndef NRF_BLE_SCAN_SLAVE_LATENCY
#define NRF_BLE_SCAN_SLAVE_LATENCY 4
#endif

// <o> NRF_BLE_SCAN_SUPERVISION_TIMEOUT - Determines the supervision time-out in units of 10 millisecond. 
#ifndef NRF_BLE_SCAN_SUPERVISION_TIMEOUT
#define NRF_BLE_SCAN_SUPERVISION_TIMEOUT 800
#endif

static ble_gap_scan_params_t m_scan_param = 
{
    .active        = 1,
    .interval      = NRF_BLE_SCAN_SCAN_INTERVAL,
    .window        = NRF_BLE_SCAN_SCAN_WINDOW,
    .timeout       = NRF_BLE_SCAN_SCAN_DURATION,
    .filter_policy = BLE_GAP_SCAN_FP_ACCEPT_ALL,
    .scan_phys     = BLE_GAP_PHY_1MBPS,
};
static ble_gap_conn_params_t m_conn_param = 
{
    .min_conn_interval  = (uint16_t)MSEC_TO_UNITS(NRF_BLE_SCAN_MIN_CONNECTION_INTERVAL, UNIT_1_25_MS),
    .max_conn_interval  = (uint16_t)MSEC_TO_UNITS(NRF_BLE_SCAN_MAX_CONNECTION_INTERVAL, UNIT_1_25_MS),
    .slave_latency      = (uint16_t)NRF_BLE_SCAN_SLAVE_LATENCY,
    .conn_sup_timeout   = (uint16_t)MSEC_TO_UNITS(NRF_BLE_SCAN_SUPERVISION_TIMEOUT, UNIT_10_MS),
};

static void scan_init(void)
{
    ret_code_t err_code;
    nrf_ble_scan_init_t init_scan;

    m_scan_param.interval = NRF_BLE_SCAN_SCAN_INTERVAL + (NRF_FICR->DEVICEADDR[0] & 0xFF);
    m_scan_param.window = m_scan_param.interval;

    m_conn_param.conn_sup_timeout = (uint16_t)MSEC_TO_UNITS(NRF_BLE_SCAN_SUPERVISION_TIMEOUT + (NRF_FICR->DEVICEADDR[0] & 0xFF)*10, UNIT_10_MS);

    memset(&init_scan, 0, sizeof(init_scan));

    init_scan.connect_if_match = true;
    init_scan.conn_cfg_tag = APP_BLE_CONN_CFG_TAG;
    init_scan.p_scan_param = &m_scan_param;
    init_scan.p_conn_param = &m_conn_param;

    err_code = nrf_ble_scan_init(&m_scan, &init_scan, scan_evt_handler);

In this page Connecting to advertisers performing extended advertising, I think I'm in the variant #4 but I never get the timeout event...

What's the best pratice for this case ?

Regards,

Gaétan

Related post: 

Parents
  • Hi,

    1) When you get the BLE_GAP_EVT_DISCONNECTED event, what is the disconnect reason? BLE_HCI_CONN_FAILED_TO_BE_ESTABLISHED(0x3E)?

    2) What SD version is this? Do you see the same issue with the latest SoftDevice version? 7.3.0?

    3) 

    generates a BLE_NUS_C_EVT_DISCONNECTED event with which I relaunch a scan_start

    Do you see the same issue if you add a random delay before calling scan_start?

  • Hi,

    1) Yes disconnect reason is BLE_HCI_CONN_FAILED_TO_BE_ESTABLISHED(0x3E)

    2) Actualy project use s140_nrf52_6.1.0_softdevice.hex, I need to change SDK version...

    3) Yes, I tried to add nrf_delay_us(NRF_FICR->DEVICEADDR[0] & 0xFF); in case BLE_NUS_C_EVT_DISCONNECTED  without change.

    Regards,

    Edit: I tried with SDK 17.1 and softdevice 7.3.0... It is the same: the dongles synchronize for a few seconds (about 3 seconds) and then the operation is OK

  • For both central and peripheral?

    I think the peripheral program is not in question because when the centrals synchronize, the peripheral does not report any status, it looks like it does not receive a coherent frame. Probably because the 3 centrals transmit perfectly at the same time and the frame received is corrupted.

    Could you try a bit bigger delay? use e.g. nrf_delay_ms() instead?

    I tried putting the same delay in ms (but I was worried that softdevice wouldn't like too long a delay in interupt time). It didn't change anything because I have the feeling that the moment of the scan start is not very important, what is important is that the 3 centrals are listening on the same channel and simultaneously receive the advertising of the peripheral... Then the 3 centrals respond in a perfectly synchronized way!

  • Hi,

    Gaétan said:
    but I was worried that softdevice wouldn't like too long a delay in interupt time

    Yeah, better to use an app_timer for this. Start a one-shot timer that expires in random time < from 0 to x ms>, and in the callback, start the scanner.

    If it's started with some delay, then it reduces the probability for the scanners to be on the same channel.

  • Hello,

    I'm sorry, but I don't think that the start time of the SCAN function is important.
    Indeed, what matters is how many centrals are listening on the channel at the moment the peripheral is advertising.

    I really feel that the problem is that several centrals are TX their response to the advertising in a perfectly synchronized way.
    In this case, it would be necessary to integrate a random time in the central between the RX of the advertising and the TX of the connection request.

  • For the moment, we regularly observe the situation of synchronization of the centrals during 2 or 3 seconds.
    Do you think that there could be a solution on the central to add a variable time between the reception of the avertising and the sending of the connection request?

  • Hi,

    Sorry for the delay.

    Gaétan said:
    Do you think that there could be a solution on the central to add a variable time between the reception of the avertising and the sending of the connection request?

    No. Not on the link-layer. But you can add some delay for when you call sd_ble_gap_connect(). The advertiser will have the radio in RX mode in a short period after sending the advertising packet. The central/scanner need to send the connection request packet in this short window after receiving the advertising packet. If you add some sending delay here, the advertiser will not receive the connection request(because the radio is no longer in RX mode). When you call sd_ble_gap_connect(), the central will listen/scan for a advertising packet(from the address you set when calling the connect function), and it will send the connection request packet if it receive a advertising packet from the specified address.

Reply
  • Hi,

    Sorry for the delay.

    Gaétan said:
    Do you think that there could be a solution on the central to add a variable time between the reception of the avertising and the sending of the connection request?

    No. Not on the link-layer. But you can add some delay for when you call sd_ble_gap_connect(). The advertiser will have the radio in RX mode in a short period after sending the advertising packet. The central/scanner need to send the connection request packet in this short window after receiving the advertising packet. If you add some sending delay here, the advertiser will not receive the connection request(because the radio is no longer in RX mode). When you call sd_ble_gap_connect(), the central will listen/scan for a advertising packet(from the address you set when calling the connect function), and it will send the connection request packet if it receive a advertising packet from the specified address.

Children
No Data
Related