DW3000 TWR on Double-Buffer Enable

I’m trying to calculate TWR with the dw3000, with double-buffer enabled. But I can’t figure out which Rx-TimeStamp I should use for distance calculations. Can you help?

I’m using the dw3000 part of the library from GitHub - Makerfabs/Makerfabs-ESP32-UWB-DW3000.

#include "dw3000.h"
#include <Arduino.h>
#include <ArduinoJson.h>
// WiFi kontroller
#include <WiFi.h>
#include "esp_wifi.h" // ESP32 Wi-Fi ayarları için gerekli kütüphane
#define WIFI_SSID "*******"
#define WIFI_PASSWORD "*********"
volatile bool internetConnect = false;
String DeviceID;

// MQTT
#include "mqtt_client.h"
#define SERVER_ADDRESS "mqtt://192.168.0.199:1883"
#define deviceEventTopic "deviceEvent"
esp_mqtt_client_handle_t client;
volatile bool MqttConnected, lastMsgSended = false;
char clien_id[18];
unsigned long lastSendPingMillis;
#define PingSendInterval 60000 // 60 sn da 1
// RTC
#include "time.h"
const char *ntpServer = "1.tr.pool.ntp.org";
const char *ntpServer2 = "2.tr.pool.ntp.org";
const char *ntpServer3 = "3.tr.pool.ntp.org";
const long gmtOffset_sec = 3600L * 3;
const int daylightOffset_sec = 0;
unsigned long unixTime;
unsigned long rtcUpdateTimeout;
#define rtcUpdatePeriod 86400000 // 3600000 saatlik 86400000  günlük
void SoftRTCUpdate(void);
void PrintTime(void);
void setTime(int32_t newTime);

// UWB
#include <SPI.h>
extern SPISettings _fastSPI;

const uint8_t PIN_RST = 7;  // reset pin
const uint8_t PIN_IRQ = 18; // irq pin
const uint8_t PIN_SS = 5;   // spi select pin
const uint8_t DW_EXTON = 4;
const uint8_t DW_WakeUp = 3;
const uint8_t DW_Sync = 19;
#define AnchorID 2 // değişebilir yapılacak

/* Default communication configuration. We use default non-STS DW mode. */
static dwt_config_t config = {
    5,                /* Channel number. */
    DWT_PLEN_128,     /* Preamble length. Used in TX only. */
    DWT_PAC8,         /* Preamble acquisition chunk size. Used in RX only. */
    9,                /* TX preamble code. Used in TX only. */
    9,                /* RX preamble code. Used in RX only. */
    1,                /* 0 to use standard 8 symbol SFD, 1 to use non-standard 8 symbol, 2 for non-standard 16 symbol SFD and 3 for 4z 8 symbol SDF type */
    DWT_BR_6M8,       /* Data rate. */
    DWT_PHRMODE_STD,  /* PHY header mode. */
    DWT_PHRRATE_STD,  /* PHY header rate. */
    (129 + 8 - 8),    /* SFD timeout (preamble length + 1 + SFD length - PAC size). Used in RX only. */
    DWT_STS_MODE_OFF, /* STS disabled */
    DWT_STS_LEN_64,   /* STS length see allowed values in Enum dwt_sts_lengths_e */
    DWT_PDOA_M0       /* PDOA mode off */
};

struct rx_data_t
{
  uint8_t frameControl;
  uint8_t snIdx;
  uint32_t sourceID;
  uint8_t sourceAddr[4];
  uint8_t destinationID;
  uint8_t data[16];
} rx_data;

/* Inter-ranging delay period, in milliseconds. */
#define RNG_DELAY_MS 1000

/* Default antenna delay values for 64 MHz PRF. See NOTE 2 below. */
#define TX_ANT_DLY 16385 // 16385
#define RX_ANT_DLY 16385 // 16385

/* Frames used in the ranging process. See NOTE 3 below. */
#define RangingRequest 0x0F
#define RangingPoll 0x10
#define RangingResponse 0x11

static uint8_t tx_poll_msg[] = {0x10, 0, 0, 0, 0, 0, AnchorID, 0, 0};
static uint8_t rx_resp_msg[] = {0x11, 0, 0x25, 0x10, 0x00, 0x98, AnchorID, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
/* Length of the common part of the message (up to and including the function code, see NOTE 3 below). */
#define ALL_MSG_COMMON_LEN 7
/* Indexes to access some of the fields in the frames defined above. */
#define FRAME_SN_IDX 1
#define RESP_MSG_POLL_RX_TS_IDX 7
#define RESP_MSG_RESP_TX_TS_IDX 11
#define RESP_MSG_TS_LEN 4
/* Frame sequence number, incremented after each transmission. */
static uint8_t frame_seq_nb = 0;

/* Buffer to store received response message.
 * Its size is adjusted to longest frame that this example code is supposed to handle. */
#define RX_BUF_LEN 20
static uint8_t rx_buffer[RX_BUF_LEN];
uint16_t frame_len;
/* Hold copy of status register state here for reference so that it can be examined at a debug breakpoint. */
static uint32_t status_reg = 0;

#define POLL_TX_TO_RESP_RX_DLY_UUS 200 // 240
#define RESP_RX_TIMEOUT_UUS 3000       // 400

/* Hold copies of computed time of flight and distance here for reference so that it can be examined at a debug breakpoint. */
static double tof;
static double distance;
extern dwt_txconfig_t txconfig_options;
#define RDB_STATUS_RXFCG0_BIT_MASK 0x01
#define RDB_STATUS_RXFR0_BIT_MASK 0x02
#define RDB_STATUS_CIADONE0_BIT_MASK 0x04
#define RDB_STATUS_CP_ERR0_BIT_MASK 0x08
#define RDB_STATUS_RXFCG1_BIT_MASK 0x10
#define RDB_STATUS_RXFR1_BIT_MASK 0x20
#define RDB_STATUS_CIADONE1_BIT_MASK 0x40
#define RDB_STATUS_CP_ERR1_BIT_MASK 0x80
uint64_t resp_rx_ts1, resp_tx_ts1;
uint64_t old_ts[3];
uint8_t ts_buf[5];
int ret;
void setup()
{
....

  // UWB
  UART_init();
  //_fastSPI = SPISettings(16000000L, MSBFIRST, SPI_MODE0);
  spiBegin(PIN_IRQ, PIN_RST);
  spiSelect(PIN_SS);
  while (!dwt_checkidlerc()) // Need to make sure DW IC is in IDLE_RC before proceeding
  {
    UART_puts("IDLE FAILED\r\n");
    while (1)
      ;
  }
  dwt_softreset();
  delay(200);

  if (dwt_initialise(DWT_DW_INIT) == DWT_ERROR)
  {
    UART_puts("INIT FAILED\r\n");
    while (1)
      ;
  }

  // Enabling LEDs here for debug so that for each TX the D1 LED will flash on DW3000 red eval-shield boards.
  dwt_setleds(DWT_LEDS_ENABLE | DWT_LEDS_INIT_BLINK);
  /* Configure DW IC. See NOTE 6 below. */
  if (dwt_configure(&config)) // if the dwt_configure returns DWT_ERROR either the PLL or RX calibration has failed the host should reset the device
  {
    UART_puts("CONFIG FAILED\r\n");
    while (1)
      ;
  }

  // /* Configure the TX spectrum parameters (power, PG delay and PG count) */
  dwt_configuretxrf(&txconfig_options);
  dwt_setdblrxbuffmode(DBL_BUF_STATE_EN, DBL_BUF_MODE_AUTO);
  //  /* Apply default antenna delay value. See NOTE 2 below. */
  dwt_setrxantennadelay(RX_ANT_DLY);
  dwt_settxantennadelay(TX_ANT_DLY);

  // /* Set expected response's delay and timeout. See NOTE 1 and 5 below.
  //  * As this example only handles one incoming frame with always the same delay and timeout, those values can be set here once for all. */
  dwt_setrxaftertxdelay(POLL_TX_TO_RESP_RX_DLY_UUS);
  dwt_setrxtimeout(0);

  // /* Next can enable TX/RX states output on GPIOs 5 and 6 to help debug, and also TX/RX LEDs
  //  * Note, in real low power applications the LEDs should not be used. */
  dwt_setlnapamode(DWT_LNA_ENABLE | DWT_PA_ENABLE);
  /* Clear good RX frame event in the DW IC status register. */
  // dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_RXFCG_BIT_MASK);

  dwt_rxenable(DWT_START_RX_IMMEDIATE);
}

void loop()
{
  // SoftRTCUpdate();
  // SendPingToDB();
  // UWB_Receive();
  UWB_Handle_Receive();
  // Serial.print(F("."));
  // delay(100);
}
void UWB_Handle_Receive()
{
  uint32_t rdb_status;
  uint32_t sys_status;

  // Ana durum register'ını ve çift arabellek durum register'ını oku
  sys_status = dwt_read32bitreg(SYS_STATUS_ID);
  rdb_status = dwt_read32bitreg(RDB_STATUS_ID);

  // Buffer 0 için kontrol
  if (rdb_status & RDB_STATUS_RXFCG0_BIT_MASK)
  {
    // Not: Ana SYS_STATUS'taki genel RXFCG biti de set edilebilir. Onu da temizleyelim.
    dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_RXFCG_BIT_MASK);

    // Buffer 0'daki veriyi oku. Önce çerçeve boyutunu al.
    // Buffer 0 aktif olduğunda, ana RX_FINFO register'ı güncel bilgiyi içerir.
    frame_len = dwt_read32bitreg(RX_FINFO_ID) & RX_FINFO_RXFLEN_BIT_MASK;
    if (frame_len <= RX_BUF_LEN)
    {
      dwt_readrxdata(rx_buffer, frame_len - FCS_LEN, 0);
      // Zaman damgasını oku
      // dwt_readrxtimestamp(ts_buf);
      // // 64-bit'e çevir
      // resp_rx_ts1 = dwt_timestamp_to_uint64(ts_buf);
      ProcessUwbFrame(rx_buffer, frame_len, 0);
      dwt_signal_rx_buff_free();
      // dwt_signal_rx_buff_free();
      dwt_writefastCMD(CMD_CLR_IRQS);
      //  Çerçeveyi işle
      //  ProcessUwbFrame(rx_buffer, frame_len, 0);
    }
    else
    {
      dwt_signal_rx_buff_free();

      dwt_writefastCMD(CMD_CLR_IRQS);
    }

    // ÖNEMLİ: SADECE Buffer 0'a ait RDB status bitlerini temizle
    // uint32_t clear_mask_0 = RDB_STATUS_RXFCG0_BIT_MASK | RDB_STATUS_RXFR0_BIT_MASK | RDB_STATUS_CIADONE0_BIT_MASK | RDB_STATUS_CP_ERR0_BIT_MASK;
    // dwt_write32bitreg(RDB_STATUS_ID, clear_mask_0);

    // ÖNEMLİ: İşlem bittiğinde arabelleği serbest bırakmak için TOGGLE komutu gönder
  }

  // Buffer 1 için kontrol
  if (rdb_status & RDB_STATUS_RXFCG1_BIT_MASK)
  {
    dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_RXFCG_BIT_MASK);

    // Buffer 1'e ait bilgileri okumak için SET_2 alanından okuma yapmak gerekir.
    // Bu genellikle dolaylı işaretçiler (indirect pointers) ile yapılır.
    // Kullandığınız API'ye bağlı olarak bu işlem değişebilir.
    // dwt_readfromdevice(0x18, 0xE8, 4) gibi bir fonksiyonla SET_2'deki RX_FINFO okunabilir.
    // Veya API'niz bunu basitleştirmiş olabilir.
    // dwt_readrxtoggleddata gibi bir fonksiyon varsa bu işi yapar.
    frame_len = dwt_read32bitreg(RX_FINFO_ID) & RX_FINFO_RXFLEN_BIT_MASK; // API'nin buffer'a göre bu register'ı güncellediğini varsayalım
    if (frame_len <= RX_BUF_LEN)
    {
      // İkinci (toggle edilmiş) buffer'dan veri oku
      dwt_readrxdata(rx_buffer, frame_len - FCS_LEN, 0);
      // Zaman damgasını oku
      // dwt_readrxtimestamp(ts_buf);
      // // 64-bit'e çevir
      // resp_rx_ts1 = dwt_timestamp_to_uint64(ts_buf);
      ProcessUwbFrame(rx_buffer, frame_len, 1);
      dwt_signal_rx_buff_free();
      dwt_writefastCMD(CMD_CLR_IRQS);
      //  Çerçeveyi işle
    }
    else
    {
      dwt_signal_rx_buff_free();
      dwt_writefastCMD(CMD_CLR_IRQS);
    }

    // ÖNEMLİ: SADECE Buffer 1'e ait RDB status bitlerini temizle
    // uint32_t clear_mask_1 = RDB_STATUS_RXFCG1_BIT_MASK | RDB_STATUS_RXFR1_BIT_MASK | RDB_STATUS_CIADONE1_BIT_MASK | RDB_STATUS_CP_ERR1_BIT_MASK;
    // dwt_write32bitreg(RDB_STATUS_ID, clear_mask_1);

    // ÖNEMLİ: İşlem bittiğinde arabelleği serbest bırak
  }

  // // Herhangi bir alıcı hatası (timeout, CRC hatası vb.) olursa
  // if (sys_status & SYS_STATUS_ALL_RX_ERR)
  // {
  //   // Tüm hata bitlerini temizle
  //   dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_ALL_RX_ERR);

  //   // Alıcıyı yeniden başlatarak dinlemeye devam etmesini sağla
  //   // Bu, alıcının bir hatadan sonra takılı kalmasını önler.
  //   dwt_rxenable(DWT_START_RX_IMMEDIATE);
  // }
}

void ProcessUwbFrame(uint8_t *frame_buffer, uint16_t frame_length, bool buffer0)
{
  UwbFrameParser(frame_buffer, frame_length);
  Serial.print(F("?"));
  Serial.print(buffer0);
  Serial.print(F(" "));
  Serial.println(rx_data.destinationID);
  // TOF hesaplama ve yanıt gönderme işlemleri burada yapılacak
  // 2. Eğer bu bize gönderilmiş bir RangingRequest ise, menzil ölçüm sürecini başlat
  resp_rx_ts1 = dwt_readrxtimestamp_from_set1() - old_ts[0];
  Serial.print(F("  0:"));
  Serial.println(resp_rx_ts1);
  old_ts[0] = resp_rx_ts1;
  resp_rx_ts1 = dwt_readrxtimestamp_from_set2() - old_ts[1];
  Serial.print(F("  1:"));
  Serial.println(resp_rx_ts1);
  old_ts[1] = resp_rx_ts1;
  resp_rx_ts1 = dwt_readrxtimestamplo32() - old_ts[2];
  Serial.print(F("  2:"));
  Serial.println(resp_rx_ts1);
  old_ts[2] = resp_rx_ts1;

  if (rx_data.destinationID == AnchorID && rx_data.frameControl == RangingRequest)
  {
    // RangingPoll mesajını hazırla

    tx_poll_msg[FRAME_SN_IDX] = frame_seq_nb;
    tx_poll_msg[2] = rx_data.sourceAddr[0];
    tx_poll_msg[3] = rx_data.sourceAddr[1];
    tx_poll_msg[4] = rx_data.sourceAddr[2];
    tx_poll_msg[5] = rx_data.sourceAddr[3];
    dwt_writefastCMD(CMD_TXRXOFF);
    // Hazırlanan mesajı DW3000'in gönderme tamponuna yaz
    Serial.print(F("  *"));
    dwt_writetxdata(sizeof(tx_poll_msg), tx_poll_msg, 0);
    dwt_writetxfctrl(sizeof(tx_poll_msg), 0, 1);

    // Yanıt beklendiğini belirterek (DWT_RESPONSE_EXPECTED) gönderimi başlat.
    // Bu komut, gönderim biter bitmez alıcıyı otomatik olarak açar.

    int ret = dwt_starttx(DWT_START_TX_IMMEDIATE | DWT_RESPONSE_EXPECTED);

    if (ret == DWT_SUCCESS)
    {
      Serial.print(F("+\n"));
      // resp_tx_ts1 = dwt_readtxtimestamplo32();
    }
    else
    {
      Serial.println("Poll TX failed!");
      // Gönderim başarısız olursa alıcıyı yeniden başlat
      dwt_rxenable(DWT_START_RX_IMMEDIATE);
    }
  }
  else if (rx_data.destinationID == AnchorID && rx_data.frameControl == RangingResponse)
  {
    // RangingResponse mesajı alındığında yapılacak işlemler
    // Serial.println("Ranging Response received.");
    frame_buffer[FRAME_SN_IDX] = 0; // SN'yi kontrol dışı bırak
    if (memcmp(frame_buffer, rx_resp_msg, ALL_MSG_COMMON_LEN) == 0)
    {
      uint64_t poll_tx_ts, resp_rx_ts;
      uint32_t poll_rx_ts, resp_tx_ts;
      int64_t rtd_init, rtd_resp;
      float clockOffsetRatio;

      // Zaman damgalarını oku
      poll_tx_ts = dwt_readtxtimestamplo32();
      resp_rx_ts = dwt_readrxtimestamplo32();
      // if (buffer0) // Buffer 0'dan geldiyse
      // {
      //   resp_rx_ts = dwt_readrxtimestamp_from_set1();
      // }
      // else // Buffer 1'den geldiyse
      // {
      //   resp_rx_ts = dwt_readrxtimestamp_from_set2();
      // }

      // resp_rx_ts = resp_rx_ts1;
      Serial.print(F("  Poll TX:"));
      Serial.print(poll_tx_ts);
      Serial.print(F(" Resp RX:"));
      Serial.println(resp_rx_ts);

      // poll_tx_ts = resp_tx_ts1;

      // Yanıt mesajının içindeki zaman damgalarını çıkar
      resp_msg_get_ts(&frame_buffer[RESP_MSG_POLL_RX_TS_IDX], &poll_rx_ts);
      resp_msg_get_ts(&frame_buffer[RESP_MSG_RESP_TX_TS_IDX], &resp_tx_ts);

      // Saat kaymasını hesapla
      clockOffsetRatio = ((float)dwt_readclockoffset()) / (uint32_t)(1 << 26);

      // Uçuş süresini (ToF) ve mesafeyi hesapla
      rtd_init = resp_rx_ts - poll_tx_ts;
      rtd_resp = resp_tx_ts - poll_rx_ts;
      tof = ((rtd_init - rtd_resp * (1 - clockOffsetRatio)) / 2.0) * DWT_TIME_UNITS;
      distance = tof * SPEED_OF_LIGHT;

      Serial.printf(" ---> DISTANCE from Tag %u: %.2f m\n", rx_data.sourceID, distance);

      // MQTT'ye gönder
      JsonDocument js;
      js["ancId"] = AnchorID;
      js["tagId"] = rx_data.sourceID;
      js["dist"] = round(distance * 100.0) / 100.0;
      String msg;
      serializeJson(js, msg);
      sendMqtt("Distance", msg);
    }
  }
}
// SET_1'den (Buffer 0 için) 40-bit RX zaman damgasını okur
uint64_t dwt_readrxtimestamp_from_set1(void)
{
  uint8_t ts_buf[5];
  uint64_t ts = 0;
  // Register File: 0x18, Offset: 0x04 (Tablo 44'e göre RX_TIME'ın SET_1'deki yeri)
  dwt_readfromdevice(0x18, 0x04, 5, ts_buf);
  for (int i = 0; i < 5; i++)
  {
    ts |= ((uint64_t)ts_buf[i]) << (i * 8);
  }
  return ts;
}
static uint64_t dwt_timestamp_to_uint64(const uint8_t *ts)
{
  uint64_t result = 0;
  result = 0;
  for (int i = 0; i < 5; i++)
  {
    result |= ((uint64_t)ts[i]) << (i * 8);
  }
  return result;
}

// SET_2'den (Buffer 1 için) 40-bit RX zaman damgasını okur
uint64_t dwt_readrxtimestamp_from_set2(void)
{
  uint8_t ts_buf[5];
  uint64_t ts = 0;
  // Register File: 0x18, Offset: 0xEC (Tablo 44'e göre RX_TIME'ın SET_2'deki yeri)
  dwt_readfromdevice(0x18, 0xEC, 5, ts_buf);
  for (int i = 0; i < 5; i++)
  {
    ts |= ((uint64_t)ts_buf[i]) << (i * 8);
  }
  return ts;
}


void UwbFrameParser(uint8_t *frame, uint16_t frame_len)
{
  rx_data.frameControl = frame[0];
  rx_data.snIdx = frame[1];

  char buf[16];
  sprintf(buf, "%02X%02X%02X%02X", frame[2], frame[3], frame[4], frame[5]);
  rx_data.sourceID = (uint32_t)strtoul(buf, NULL, 10);
  rx_data.sourceAddr[0] = frame[2];
  rx_data.sourceAddr[1] = frame[3];
  rx_data.sourceAddr[2] = frame[4];
  rx_data.sourceAddr[3] = frame[5];
  rx_data.destinationID = frame[6];
  return;
  if (frame_len > 9)
  {
    for (int i = 0; i < 16; i++)
    {
      rx_data.data[i] = frame[7 + i];
      if (9 + i >= frame_len)
        break;
    }
  }
  Serial.print("  Frame Control:");
  Serial.println(rx_data.frameControl, HEX);
  Serial.print(F("  Sn IDx:"));
  Serial.println(rx_data.snIdx);
  Serial.print(F("  Source ID:"));
  Serial.println(rx_data.sourceID);
  Serial.print(F("  Destination ID:"));
  Serial.println(rx_data.destinationID);
  Serial.print(F("  Data:"));
  for (int i = 0; i < 16; i++)
  {
    Serial.print(rx_data.data[i], HEX);
    Serial.print("-");
    if (9 + i >= frame_len)
      break;
  }
  Serial.println();
}

...

/*****************************************************************************************************************************************************
 *  * Kayapınar UWB Mesaj Format
 *  Frame Control 1 octet - Mesaj Tipi
 *    0x01 Blink
 *    0x0F Range Request
 *    0x10 Range Poll
 *    0x11 Range Response
 *  SN Index 1 octet - Frame sıra numarası 0-255
 *  Source ID 4 octet - Cihaz ID'si
 *  Destination ID 1 octet - Anchor ID'si
 *  Data 0-15 octet - Mesaj içeriği
 *  FCS 2 octet - Frame Check Sequence (Otomatik olarak DW IC tarafından eklenir)
 * *****************************************************************************************************************************************************
 *
 * NOTES:
 *
 * 1. The single-sided two-way ranging scheme implemented here has to be considered carefully as the accuracy of the distance measured is highly
 *    sensitive to the clock offset error between the devices and the length of the response delay between frames. To achieve the best possible
 *    accuracy, this response delay must be kept as low as possible. In order to do so, 6.8 Mbps data rate is used in this example and the response
 *    delay between frames is defined as low as possible. The user is referred to User Manual for more details about the single-sided two-way ranging
 *    process.  NB:SEE ALSO NOTE 11.
 *
 *    Initiator: |Poll TX| ..... |Resp RX|
 *    Responder: |Poll RX| ..... |Resp TX|
 *                   ^|P RMARKER|                    - time of Poll TX/RX
 *                                   ^|R RMARKER|    - time of Resp TX/RX
 *
 *                       <--TDLY->                   - POLL_TX_TO_RESP_RX_DLY_UUS (RDLY-RLEN)
 *                               <-RLEN->            - RESP_RX_TIMEOUT_UUS   (length of response frame)
 *                    <----RDLY------>               - POLL_RX_TO_RESP_TX_DLY_UUS (depends on how quickly responder can turn around and reply)
 *
 *
 * 2. The sum of the values is the TX to RX antenna delay, this should be experimentally determined by a calibration process. Here we use a hard coded
 *    value (expected to be a little low so a positive error will be seen on the resultant distance estimate). For a real production application, each
 *    device should have its own antenna delay properly calibrated to get good precision when performing range measurements.
 * 3. The frames used here are Decawave specific ranging frames, complying with the IEEE 802.15.4 standard data frame encoding. The frames are the
 *    following:
 *     - a poll message sent by the initiator to trigger the ranging exchange.
 *     - a response message sent by the responder to complete the exchange and provide all information needed by the initiator to compute the
 *       time-of-flight (distance) estimate.
 *    The first 10 bytes of those frame are common and are composed of the following fields:
 *     - byte 0/1: frame control (0x8841 to indicate a data frame using 16-bit addressing).
 *     - byte 2: sequence number, incremented for each new frame.
 *     - byte 3/4: PAN ID (0xDECA).
 *     - byte 5/6: destination address, see NOTE 4 below.
 *     - byte 7/8: source address, see NOTE 4 below.
 *     - byte 9: function code (specific values to indicate which message it is in the ranging process).
 *    The remaining bytes are specific to each message as follows:
 *    Poll message:
 *     - no more data
 *    Response message:
 *     - byte 10 -> 13: poll message reception timestamp.
 *     - byte 14 -> 17: response message transmission timestamp.
 *    All messages end with a 2-byte checksum automatically set by DW IC.
 * 4. Source and destination addresses are hard coded constants in this example to keep it simple but for a real product every device should have a
 *    unique ID. Here, 16-bit addressing is used to keep the messages as short as possible but, in an actual application, this should be done only
 *    after an exchange of specific messages used to define those short addresses for each device participating to the ranging exchange.
 * 5. This timeout is for complete reception of a frame, i.e. timeout duration must take into account the length of the expected frame. Here the value
 *    is arbitrary but chosen large enough to make sure that there is enough time to receive the complete response frame sent by the responder at the
 *    6.8M data rate used (around 200 µs).
 * 6. In a real application, for optimum performance within regulatory limits, it may be necessary to set TX pulse bandwidth and TX power, (using
 *    the dwt_configuretxrf API call) to per device calibrated values saved in the target system or the DW IC OTP memory.
 * 7. dwt_writetxdata() takes the full size of the message as a parameter but only copies (size - 2) bytes as the check-sum at the end of the frame is
 *    automatically appended by the DW IC. This means that our variable could be two bytes shorter without losing any data (but the sizeof would not
 *    work anymore then as we would still have to indicate the full length of the frame to dwt_writetxdata()).
 * 8. We use polled mode of operation here to keep the example as simple as possible but all status events can be used to generate interrupts. Please
 *    refer to DW IC User Manual for more details on "interrupts". It is also to be noted that STATUS register is 5 bytes long but, as the event we
 *    use are all in the first bytes of the register, we can use the simple dwt_read32bitreg() API call to access it instead of reading the whole 5
 *    bytes.
 * 9. The high order byte of each 40-bit time-stamps is discarded here. This is acceptable as, on each device, those time-stamps are not separated by
 *    more than 2**32 device time units (which is around 67 ms) which means that the calculation of the round-trip delays can be handled by a 32-bit
 *    subtraction.
 * 10. The user is referred to DecaRanging ARM application (distributed with EVK1000 product) for additional practical example of usage, and to the
 *     DW IC API Guide for more details on the DW IC driver functions.
 * 11. The use of the clock offset value to correct the TOF calculation, significantly improves the result of the SS-TWR where the remote
 *     responder unit's clock is a number of PPM offset from the local initiator unit's clock.
 *     As stated in NOTE 2 a fixed offset in range will be seen unless the antenna delay is calibrated and set correctly.
 * 12. In this example, the DW IC is put into IDLE state after calling dwt_initialise(). This means that a fast SPI rate of up to 20 MHz can be used
 *     thereafter.
 * 13. Desired configuration by user may be different to the current programmed configuration. dwt_configure is called to set desired
 *     configuration.
 ****************************************************************************************************************************************************/

dwt_configciadiag (DW_CIA_DIAG_LOG_MIN);

Adding this was the solution. For your information :slight_smile: