[DWM3001CDK]What should I do to start ranging between the two boards?

So, I’m definitely getting some response by the Responder when the Initiator is powered up, however I’m not getting any ranging data.

I suspect that something is wrong with my configurations, as mentioned by @carlos.silva, but I’m unsure where to start to resolve this. One thing I was suspecting is that perhaps the two units are using the same address, but it’s unclear how to verify or set these.

Many thanks, since your suggestions above have been helping me make progress, but there’s still a bit further to get it to work property.

Any guidance on how to debug through this is very welcome. See details below in the next reply.

Sorry, made an error in my previous replies, so correcting here. I’ve made progress, but still not ranging properly. Here is what I’ve uncovered.

I’m using two DWM3001CDK to work toward Two-Way Ranging TWR. My starting point is the code for the tag to be used with the provided iPhone app.

I deleted the ble and niq initializations in main.c. I finally realized that the main_uwb.c function called _defaultTask is not properly setting up the controllER versus controllEE. With the current code, it was always setting the unit as “controlEE”. So, to make it work, I added a variable ranging_role that I could set to 0/1 for Responder/Initiator (same as the value set in ACCESSORY_RANGING_ROLE). See snippet of code below. You will also need to create a:
static uint32_t ranging_role = 1; /**< Responder 0, Initiator 1 */

[Note: I struggled for a bit since I first tried using AppSetFiRaRole and AppGetFiRaRole, but I can’t seem to make sense about what they are doing. I try setting with a value and then I read back a different value (that’s strange). These two functions are also used in construct_fira_param_from_config so they may require additional scrutiny in that function too.]

Current behavior is still not providing measurements, but at least there is some back and forth communications.

  • If I plug in Responder alone, there is no report printed, it just waits. D13 flashes Red

  • If I plug in Initiator alone, there is a string of ERR ranging reports printed, with increasing Block Index. D13 flashes Yellow and Red:

report_cb ->
report_cb <-
{"TWR": {"R":54,"a16":"0x0001","S":"ERR","D cm":0}}
report_cb ->
report_cb <-
{"TWR": {"R":55,"a16":"0x0001","S":"ERR","D cm":0}}
report_cb ->
report_cb <-
{"TWR": {"R":56,"a16":"0x0001","S":"ERR","D cm":0}}
report_cb ->
report_cb <-
{"TWR": {"R":57,"a16":"0x0001","S":"ERR","D cm":0}}
report_cb ->
  • If I plug in the Responder, and subsequently plug in the Initiator and watch the response on the responder, I start start to see a string of ERR ranging reports, all with a Block Index = 1. Responder D13 flashes Red, Initiator D13 flashes Yellow and Red.
report_cb ->
report_cb <-
{"TWR": {"R":1,"a16":"0x0001","S":"ERR","D cm":0}}
report_cb ->
report_cb <-
{"TWR": {"R":1,"a16":"0x0001","S":"ERR","D cm":0}}
report_cb ->
report_cb <-
{"TWR": {"R":1,"a16":"0x0001","S":"ERR","D cm":0}}
report_cb ->
report_cb <-
{"TWR": {"R":1,"a16":"0x0001","S":"ERR","D cm":0}}
report_cb ->
report_cb <-
{"TWR": {"R":1,"a16":"0x0001","S":"ERR","D cm":0}}

/* 
 * This task will start an Accessory as a UWB Initiator or UWB Responder
 * 
 */
static void _defaultTask(const void *arg)
{
    char str[256];
    osEvent evt;
    fira_param_t *fira_param = get_fira_config();
    param_block_t* app_config = AppConfigGet();

    char result[256];
    snprintf(result, sizeof(result), "_defaultTask ->\n");            
    port_tx_msg(result, strlen(result));

    int Signal = SIGNAL_START_INIT | SIGNAL_START_RESP | SIGNAL_STOP_ALL;

    while(1)
    {
        osMutexRelease(defaultTask.MutexId);
        evt = osSignalWait(Signal, 10000);
        osMutexWait(defaultTask.MutexId, 0);

        nrfx_wdt_feed();

        if(evt.status == osEventTimeout)
        {
            display_threads_heap_usage();
            continue;
        }

        fira_terminate();

        disable_dw3000_irq();

        /**/

        snprintf(result, sizeof(result), "ResumeUWBTasks: evt.value_signals %d\n", evt.value.signals);            
        port_tx_msg(result, strlen(result));

               
        snprintf(result, sizeof(result), "_defaultTask - AppGetFiraRole: %d\n", AppGetFiRaRole());            
        port_tx_msg(result, strlen(result));


        if (ranging_role == 1) {
          construct_fira_param_from_config(fira_param, (void*)&AppConfigGet()->s.fira_config, 1);
          fira_helper_controller((void const *)fira_param);

        } else {
          construct_fira_param_from_config(fira_param, (void*)&AppConfigGet()->s.fira_config, 0);
          fira_helper_controlee((void const *)fira_param);
          }
        
    }

    snprintf(result, sizeof(result), "_defaultTask <-\n");            
    port_tx_msg(result, strlen(result));
}

I finally got double-sided two way ranging working. In addition to above changes, I needed to configure the short address and destination addresses so that the units would recognize each other.

I initially just hacked the <default_config.h> to verify it, but then eventually updated the construct_fira_param_from_config function in <main_uwb.c> to adjust the addresses based on the ACCESSORY_RANGING_ROLE.

Onward!

@kmatch98 Could you share the detail of fira_param?Tks so much.
controlee’s dest…addr is equal to controler’s short_addr,but it doesn’t work.

@kmatch98 Congrats, as Doney said, could you share some details of fira_param?
Tks so much.

@ kmatch98, Do we need to change SRC_ADDR and DST_ADDR each other?

Thanks for your patience, I was away from this for a couple of days. Here is my latest code for the function construct_fira_param_from_config from main_uwb.c. I modified the main_uwb function to pass the parameter ACCESSORY_RANGING_ROLE from main.c. This way I can keep the same set of code for the tag and anchor by just changing the ACCESSORY_RANGING_ROLE.

Note: I initially tried setting the Initiator/Responder based on AppSetFiraRole and AppGetFiraRole, but it acted strange, so I just fell back to passing a parameter to the main_uwb function.

Let me know if you have any success or if you encounter other difficulties.

-kmatch

construct_fira_param_from_config(fira_param_t *fira_param, fira_device_configure_t *config, int controller)
{

    char result[256];
    snprintf(result, sizeof(result), "construct_fira_param_from_config ->\n");            
    port_tx_msg(result, strlen(result));

    /*PHY config*/
    fira_param->dwt_config. txPreambLength = DWT_PLEN_64;
    fira_param->dwt_config. rxPAC     = DWT_PAC8;
    fira_param->dwt_config. dataRate  = DWT_BR_6M8;
    fira_param->dwt_config. phrMode   = DWT_PHRMODE_STD;
    fira_param->dwt_config. phrRate   = DWT_PHRRATE_STD;
    fira_param->dwt_config. sfdTO     = 65;             
    fira_param->dwt_config. stsMode   = DWT_STS_MODE_OFF;
    fira_param->dwt_config. stsLength = DWT_STS_LEN_64;
    fira_param->dwt_config. pdoaMode  = DWT_PDOA_M0;

    /* Configure specific fira app parameters */
    fira_param->dwt_config. sfdType   = (config->SP0_PHY_Set == BPRF_SET_2)?(DWT_SFD_IEEE_4Z):(DWT_SFD_IEEE_4A);
    fira_param->dwt_config. chan      = config->Channel_Number;
    fira_param->dwt_config. txCode    = config->Preamble_Code;
    fira_param->dwt_config. rxCode    = config->Preamble_Code;


    /* MAC configure */
    // fira_param->short_addr = AR2U16(config->SRC_ADDR); /* see below */
    fira_param->session_id = config->Session_ID;
    fira_param->session.initiation_time_ms = config->UWB_Init_Time_ms;

    snprintf(result, sizeof(result), "construct - 0\n");            
    port_tx_msg(result, strlen(result));

    snprintf(result, sizeof(result), "controller: %d\n", controller);            
    port_tx_msg(result, strlen(result));

    AppSetFiRaRole(controller);

    snprintf(result, sizeof(result), "AppGetFiRaRole: %d\n", AppGetFiRaRole());            
    port_tx_msg(result, strlen(result));

    if (controller == 1) { /* Initiator: 1 */
            fira_param->session.device_type = FIRA_DEVICE_TYPE_CONTROLLER;
            fira_param->session.device_role = FIRA_DEVICE_ROLE_INITIATOR;
            fira_param->short_addr = 98; /* override settings in <default_config.h> */
            fira_param->session.destination_short_address = 9;

    } else { /* Responder: 0 */
            fira_param->session.device_type = FIRA_DEVICE_TYPE_CONTROLEE;
            fira_param->session.device_role = FIRA_DEVICE_ROLE_RESPONDER;
            fira_param->short_addr = 9;
            fira_param->session.destination_short_address = 98;
    }

    snprintf(result, sizeof(result), "construct - 1\n");            
    port_tx_msg(result, strlen(result));
    
    /* Only supporting Deferred DS-TWR */
    fira_param->session.ranging_round_usage = config->Ranging_Round_Usage;
    fira_param->session.rframe_config = config->Rframe_Config;
    fira_param->session.sfd_id = (config->SP0_PHY_Set == BPRF_SET_2)?(FIRA_SFD_ID_2):(FIRA_SFD_ID_0);
    fira_param->session.slot_duration_rstu = config->Slot_Duration_RSTU;
    fira_param->session.block_duration_ms = config->Block_Duration_ms;
    fira_param->session.round_duration_slots = config->Round_Duration_RSTU / config->Slot_Duration_RSTU;
    fira_param->session.multi_node_mode = config->Multi_Node_Mode;

    fira_param->session.round_hopping = config->Round_Hopping;
    fira_param->session.report_tof = config->ToF_Report;


    snprintf(result, sizeof(result), "----- short_addr: 0x%04x\n", fira_param->short_addr);            
    port_tx_msg(result, strlen(result));
    snprintf(result, sizeof(result), "----- session_id: %d\n", fira_param->session_id);            
    port_tx_msg(result, strlen(result));
    
    // fira_param->session.destination_short_address = AR2U16(config->DST_ADDR); /* see above */
    snprintf(result, sizeof(result), "----- destination_short_addr: 0x%04x\n", fira_param->session.destination_short_address);            
    port_tx_msg(result, strlen(result));

    fira_param->controlees_params.n_controlees = config->Number_of_Controlee;
    fira_param->controlees_params.controlees[0].address = fira_param->session.destination_short_address;

    fira_param->session.vupper64[7] = config->Vendor_ID[0];
    fira_param->session.vupper64[6] = config->Vendor_ID[1];
    fira_param->session.vupper64[5] = config->Static_STS_IV[0];
    fira_param->session.vupper64[4] = config->Static_STS_IV[1];
    fira_param->session.vupper64[3] = config->Static_STS_IV[2];
    fira_param->session.vupper64[2] = config->Static_STS_IV[3];
    fira_param->session.vupper64[1] = config->Static_STS_IV[4];
    fira_param->session.vupper64[0] = config->Static_STS_IV[5];

    /* Get parameters from global configuration. */
    fira_param->session.channel_number = config->Channel_Number;
    fira_param->session.preamble_code_index = config->Preamble_Code;

    /* Do not change below parameters */
    fira_param->session.rx_antenna_selection = 0;
    fira_param->session.rx_antenna_pair_azimuth = 0xFF;
    fira_param->session.rx_antenna_pair_elevation = 0xFF;
    fira_param->session.tx_antenna_selection = 1;
    fira_param->session.rx_antenna_switch = 0;
    fira_param->session.aoa_result_req = 0;
    fira_param->session.report_aoa_azimuth = 0;
    fira_param->session.report_aoa_fom = 0;

    snprintf(result, sizeof(result), "construct_fira_param_from_config <-\n");            
    port_tx_msg(result, strlen(result));
}

1 Like

@kmatch98 @carlos.silva Tks both very much, we finally got double-sided two way ranging working.

1 Like

@kmatch98 We face another problem when want to range with two responseres. We changed the ‘destination_short_address’ from 9 to 10, but the results are the same for 9. We do not know why it does not reset successfully.

    if(evt.status == osEventTimeout)
    {
        display_threads_heap_usage();
        snprintf(result, sizeof(result), "osEventTimeout ->\n");            
        port_tx_msg(result, strlen(result));

        construct_fira_param_from_config(fira_param, (void*)&AppConfigGet()->s.fira_config, 1,10);
        fira_helper_controller_1((void const *)fira_param);

        continue;
    }

    void fira_helper_controller_1(void const *arg)
    {
        fira_param = (fira_param_t *)arg;
        fira_helper_set_session_parameters(session_id,
                                           &fira_param->session);
        fira_helper_add_controlees(session_id,
                                           &fira_param->controlees_params);

}

@kmatch98 Thank u so much.After changing addr, it works well. :+1: :+1: :+1:
@carlos.silva Thank u for your patient guidance.At now i finally understand your words.

1 Like

@Doney ,Congrats. Do you try to range with two responseres at the same time?

sorry,i didn’t try that because i just have only two boards.

Thanks for all the good feedback. Glad y’all are getting it working. Please send an update if you ever get the multiple tags working.

-kmatch

Hi!
I’m trying to replicate your results, but I’m a little stuck.
For your final version, did you maintain your changes in the _defaultTask function or just used the original one and just changed the construct_fira_param_from_config one?
It would be great if you can upload the project to compare and check if I messed up, following the conversation…

I’ve been able to flash the DWM3001CDK boards and I get the message:

00> ACCESSORY_RANGING_ROLE: Initiator
00> _defaultTask →

(or Responder for the other one) but it gets stuck in that print and doesn’t seem to be doing any ranging yet…

Thanks!

Hey @barratia I solved the problem by setting up before the while the receptor / initiator.
I’m able to get the data and it’s working.
Here the code updated :

static void _defaultTask(const void *arg)
{
    char str[256];
    osEvent evt;
    fira_param_t *fira_param = get_fira_config();
    param_block_t* app_config = AppConfigGet();

    char result[256];
    snprintf(result, sizeof(result), "_defaultTask ->\n");            
    port_tx_msg(result, strlen(result));

    int Signal = SIGNAL_START_INIT | SIGNAL_START_RESP | SIGNAL_STOP_ALL;

    if (ranging_role == 1) {
      construct_fira_param_from_config(fira_param, (void*)&AppConfigGet()->s.fira_config, 1);
      fira_helper_controller((void const *)fira_param);

    } else {
      construct_fira_param_from_config(fira_param, (void*)&AppConfigGet()->s.fira_config, 0);
      fira_helper_controlee((void const *)fira_param);
      }


    while(1)
    {
        osMutexRelease(defaultTask.MutexId);
        evt = osSignalWait(Signal, 10000);
        osMutexWait(defaultTask.MutexId, 0);

        nrfx_wdt_feed();

        if(evt.status == osEventTimeout)
        {
            display_threads_heap_usage();
            continue;
        }

        fira_terminate();

        disable_dw3000_irq();

        /**/

        snprintf(result, sizeof(result), "ResumeUWBTasks: evt.value_signals %d\n", evt.value.signals);            
        port_tx_msg(result, strlen(result));

               
        snprintf(result, sizeof(result), "_defaultTask - AppGetFiraRole: %d\n", AppGetFiRaRole());            
        port_tx_msg(result, strlen(result));


        if (ranging_role == 1) {
          construct_fira_param_from_config(fira_param, (void*)&AppConfigGet()->s.fira_config, 1);
          fira_helper_controller((void const *)fira_param);

        } else {
          construct_fira_param_from_config(fira_param, (void*)&AppConfigGet()->s.fira_config, 0);
          fira_helper_controlee((void const *)fira_param);
          }
        
    }

    snprintf(result, sizeof(result), "_defaultTask <-\n");            
    port_tx_msg(result, strlen(result));
}

1 Like

@kmatch98 @zyliu @Doney Any updates about multiple responseres at the same time? I will try to spend some times on it.

Which function should I change when I want to start ranging between two boards in the latest version of qorvo (Qorvo_Nearby_Interaction_3_1_0)?
I would be so appreciate if someone give some help.

Hello @Neuse !

For TWR between two boards, I recommend you use the Software Preview:

The DWM3001CDK Software Preview is available on the DWM3001CDK product page [Tab Documents]:
https://www.qorvo.com/products/p/DWM3001CDK#documents

Is named “DWM3001CDK DK Software, Sources, Tools and Developer Guide”, here is the direct link if preferred:
DWM3001CDK DK Software, Sources, Tools and Developer Guide

There you will find applications for FiRa TWR implementing UCI (UWB Command Interface) and a CLI (Command Line Interface) app.
I recommend you try the CLI first, you can flash two boards and explore the configuration commands, then use “respf” to start one board as a responder and “initf” to start the other board as an initiator, then they will start TWR immediately.

Kind regards!

Hi @carlos.silva !

I successfully obtained “DWM3001CDK DK Software, Sources, Tools and Developer Guide”.
I would like to develop using Murata Type2AB (nRF52840 +QM33120W), is it compatible?

Thank you!

I found the QM33120W software at
QM33 DK Software, Sources, Tools and Developer Guide
I’ll try working on this.

1 Like