Synchronisation errors with Distance Measurement (DM)

Hello and thank you for your help.

I am working on a project that requires a separate initiator and reflector for MCPD distance measurement. I believe the sample assumes a dual initiator-reflector role for all devices involved in the measurement. I am attempting to use the distance measurement library from the API documentation, but I seem to have issues synchronising the initiator and reflector.

I am using the same method of synchronising DM request additions as the sample. The reflector adds requests as part of the callback when its advertisement is scanned:

static void adv_scanned_cb(struct bt_le_ext_adv *adv,
			struct bt_le_ext_adv_scanned_info *info) {
	struct dm_request req;

	bt_addr_le_copy(&req.bt_addr, info->addr);
	req.role = DM_ROLE_REFLECTOR;
	req.ranging_mode = DM_RANGING_MODE_MCPD;
	req.rng_seed = sys_rand32_get();
	req.start_delay_us = 0;
	req.extra_window_time_us = 0;

	int err = dm_request_add(&req);
	if (err) printk("Error adding DM request: %d\n", err);
	else printk("DM request added.\n");
}

The initiator adds DM requests when its BLE scan filters match the advertisement sent by the relfector:

bool handle_adv(struct bt_data *data, void *user_data) {
	struct dm_request req;

    switch(data->type) {
		case BT_DATA_UUID128_ALL:
			bt_addr_le_copy(&req.bt_addr, user_data);
			req.role = DM_ROLE_INITIATOR;
			req.ranging_mode = DM_RANGING_MODE_MCPD;
			req.rng_seed = sys_rand32_get();
			req.start_delay_us = 0;
			req.extra_window_time_us = 0;

			int err = dm_request_add(&req);
			if (err) printk("Error adding DM request:%d\n", err);
			else printk("DM request added.\n");

			return false;
		default:
			return true;
	}

	return true;
}

The data_ready callback set with dm_init was never called on either side. I found that the calculation() function in dm.h was never called in the dm_thread, where the nrf_dm_status was always set to 1 (NRF_DM_STATUS_FAIL_SYNC).

if (dm_context.nrf_dm_status == NRF_DM_STATUS_SUCCESS) {
	calculation();
} else {
	LOG_DBG("Ranging failed (nrf_dm status: %d)",
					  dm_context.nrf_dm_status);
}

And this was because nrf_dm_proc_execute() would always fail in mpsl_timeslot_callback().

nrf_dm_status = nrf_dm_configure(&dm_config);
LOG_DBG("Status after configuration: %d\n", nrf_dm_status); // always 0

if (nrf_dm_status == NRF_DM_STATUS_SUCCESS) {
	nrf_dm_status = nrf_dm_proc_execute(timeslot_ctx.curr_req.window_length_us);
	LOG_DBG("Status after proc_execute: %d\n", nrf_dm_status); // always 1
}

A previous question (Concerns about Distance Measurement library ) was asked regarding a similar problem, and the response mentioned using the delay and extending the length of the measurement window. May I know whether this is supposed to be on the initiator or reflector side and what the typical values might be? I've tried a large range and still had the same problem so I was hoping for some clarity on this.

I have CONFIG_DM_MIN_TIME_BETWEEN_TIMESLOTS_US set to 5000 on both initiator and reflector and CONFIG_DM_INITIATOR_DELAY_US at 2000 on the initiator.

Device used: 2 nRF52840DKs

SDK: nRF Connect v2.2.99

Thank you.

  • I just re-read the documentation and realised the rng seed should be the same on both initiator and reflector. Will update once I fix that issue.

  • Let me know if you're still having trouble after setting the rng_seed values identical on initiator and reflector!

    Best regards,

    Simon

  • I tried that and everything seems to work fine now. I didn't realise it was that trivial of an error. Thanks for your help anyway!

  • Hi,

      have you used connection oriented or connection less ble communication? 

    If Connection oriented, then can you please suggest when to trigger dm_add_request() on both sides.

    Best regards,

    syed

  • I used the same method as the DM sample, connection oriented BLE with dm_request_add() triggered as part of the advertising callbacks. 

    On the initiator side, I called dm_request_add() in the callback for matching scan filters:

    bool handle_adv(struct bt_data *data, void *user_data) {
    	struct dm_request req;
    
        switch(data->type) {
    		case BT_DATA_UUID128_ALL:
    			bt_addr_le_copy(&req.bt_addr, user_data);
    			req.role = DM_ROLE_INITIATOR;
    			req.ranging_mode = DM_RANGING_MODE_MCPD;
    			req.rng_seed = sys_cpu_to_le32(RNG_SEED);
    			req.start_delay_us = 0;
    			req.extra_window_time_us = 0;
    
    			dm_request_add(&req); // this is where dm is triggered
    			break;
    	}
    
    	return true;
    }
    
    static void scan_filter_match(struct bt_scan_device_info *device_info,
    					struct bt_scan_filter_match *filter_match,
    					bool connectable)
    {
    	bt_addr_le_t addr;
    
    	bt_addr_le_copy(&addr, device_info->recv_info->addr);
    	bt_data_parse(device_info->adv_data, handle_adv, &addr);
    }
    
    BT_SCAN_CB_INIT(scan_cb, scan_filter_match, NULL, NULL, NULL);

    On the reflector side, it's called during the extended advertising callback for when the reflector's BLE advertisement is scanned:

    static void adv_scanned_cb(struct bt_le_ext_adv *adv,
    			struct bt_le_ext_adv_scanned_info *info) {
    	struct dm_request req;
    
    	bt_addr_le_copy(&req.bt_addr, info->addr);
    	req.role = DM_ROLE_REFLECTOR;
    	req.ranging_mode = DM_RANGING_MODE_MCPD;
    	req.rng_seed = sys_cpu_to_le32(RNG_SEED);
    	req.start_delay_us = 0;
    	req.extra_window_time_us = 0;
    
    	dm_request_add(&req);
    }
    
    const static struct bt_le_ext_adv_cb adv_cb = {
    	.scanned = adv_scanned_cb,
    };

    adv_cb is just from the external advertisement creation in start_adv().

    err = bt_le_ext_adv_create(adv_param, &adv_cb, &adv);

    I stuck to what the sample used, but there might be other ways to do it.

Related