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.
****************************************************************************************************************************************************/