Factory‑Calibrated `xtal_trim` Overridden by Default in SDK Build? (DWM3001CDK)

Hi everyone,

I’m using the latest SDK v1.0.2 for the DWM3001CDK.

The user manual states that each board’s clock is factory‑calibrated and its xtal_trim value is written to OTP. After flashing the firmware and running LISTCAL, I see that my board’s xtal_trim is 20.

However, when I print the configurations before running the FiRa application by doing this:

static void fira_app_process_start(void)
{
    /* OK, let's start. */
    int r = uwbmac_start(uwbmac_ctx);
    assert(r == QERR_SUCCESS);
    /* Start session. */
    r = fira_helper_start_session(&fira_ctx, session_handle);
    assert(r == QERR_SUCCESS);
    started = true;
    listener_cfg(); // print configurations
}

The listener_cfg() is defined in cmd_fn.c and I guess it is for debugging:

void listener_cfg(void)
{
    int hlen, str_len;
    char *str = qmalloc(MAX_STR_SIZE);
    dwt_app_config_t *dwt_app_config = get_app_dwt_config();
    dwt_config_t *dwt_config = &dwt_app_config->dwt_config;

    str_len = sprintf(str, "JS%04X", 0x5A5A); // reserve space for length of JS object
    hlen = str_len;
    str_len += sprintf(&str[str_len], "{\"LCFG PARAM\":{\r\n");

    str_len += sprintf(&str[str_len], "\"CHAN\":%d,\r\n", deca_to_chan(dwt_config->chan));
    str_len += sprintf(&str[str_len], "\"txPreamble\":%d,\r\n", dwt_config->txPreambLength);
    str_len += sprintf(&str[str_len], "\"PAC\":%d,\r\n", deca_to_pac(dwt_config->rxPAC));
    str_len += sprintf(&str[str_len], "\"TXPCODE\":%d,\r\n", deca_to_preamble_code(dwt_config->txCode));
    str_len += sprintf(&str[str_len], "\"PCODE\":%d,\r\n", deca_to_preamble_code(dwt_config->rxCode));
    str_len += sprintf(&str[str_len], "\"SFDTYPE\":%d,\r\n", deca_to_sfd_type(dwt_config->sfdType));
    str_len += sprintf(&str[str_len], "\"DRATE\":%d,\r\n", deca_to_bitrate(dwt_config->dataRate));
    str_len += sprintf(&str[str_len], "\"PHRMODE\":%d,\r\n", deca_to_phr_mode(dwt_config->phrMode));
    str_len += sprintf(&str[str_len], "\"PHRRATE\":%d,\r\n", deca_to_phr_rate(dwt_config->phrRate));
    str_len += sprintf(&str[str_len], "\"SFDTO\":%d,\r\n", dwt_config->sfdTO);
    str_len += sprintf(&str[str_len], "\"STSMODE\":%d,\r\n", deca_to_sts_mode(dwt_config->stsMode));
    str_len += sprintf(&str[str_len], "\"STSLEN\":%d,\r\n", deca_to_sts_length(dwt_config->stsLength));
    str_len += sprintf(&str[str_len], "\"PDOAMODE\":%d,\r\n", deca_to_pdoa_mode(dwt_config->pdoaMode));
    str_len += sprintf(&str[str_len], "\"XTALTRIM\":%u}}", dwt_app_config->xtal_trim);

    /* Add formatted 4X of length, this will erase first '{' */
    sprintf(&str[2], "%04X", str_len - hlen);
    /* Restore the start bracket. */
    str[hlen] = '{';
    str_len += sprintf(&str[str_len], "\r\n");
    reporter_instance.print((char *)str, str_len);

    qfree(str);
}

Through here I saw the xtal_trim is now 46, and it is the default xtal_trim value defined in the deca_device_api.h:

#define DEFAULT_XTAL_TRIM 0x2EU

According to the comments, the default should be used only if no OTP value exists. My board definitely has an OTP value (20), so why is the firmware still falling back to the default?

Because one xtal_trim step is around 1.65 ppm, this 26‑step difference adds up to ~43 ppm of error—quite large. DS‑TWR will cancel out clock error, but this still feels like a firmware issue. Am I interpreting the behaviour correctly, or is there something I’m missing?

Thanks for any insight!

Shanmu

Hello,

Listener is different from the other applications (initf, respf…): it is not a Fira Application and it does use the provided config_manager library.

The CLI command CALKEY calls the l1 configuration API (l1_config_read_keyfor instance). It helps to set/get calib&config keys. Then when using FiRa ranging, the uwb-stack will retrieve the configuration and calibration through the same API.

The Listener application does not use any of these pre-compiled libraries, it call bare driver API. So it uses the configuration values set in the driver_app_config.c.

The way you are doing in your code is preparing a FiRa ranging, but dumping a configuration which is not used. If you want to set/get the configuration programmatically for FiRa, check how it is done in the cmd_calibration.c file.

I hope it helps.