I am currently using DWM3000 EVK with NRF58240DK for a UWB indoor localization system. I want to use the timer to setup a localization period for each tag node. I tried several values. For the dely = 5000ms, it is normal. For the delay = 1000ms, it is normal. For delay = 500ms, it acts really weird. I burned the code to the board with Segger and the period was 1000ms. Then, I redid the same steps and the period became 500ms. After I shut down and reboot the board, it becamee 1000ms again. The period is really really confusing. I don't know what happened. Could you please take a look for me? Thank you! The below is the code. I have a collision detection in the code but I tested with only one board so no collision should happen.
#include <boards.h>
#include <deca_spi.h>
#include <port.h>
#include <sdk_config.h>
#include <stdio.h>
#include <stdlib.h>
#include "deca_probe_interface.h"
#include <config_options.h>
#include <deca_device_api.h>
#include <deca_spi.h>
#include <port.h>
#include <shared_defines.h>
#include <shared_functions.h>
#include "nrf_drv_timer.h"
#include "nrf_drv_rng.h"
#include "nrf_delay.h"
#ifndef DW_TWR_TRANS
#define DW_TWR_TRANS
// This is UWB Transmission Configuration
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 */
};
#define RNG_DELAY_US 100
#define PERIOD_DELAY_MS 500 // This is the delay for localization. It is not working properly.
#define COLLISION_SENSING_DELAY_US 1000 // This delay is for sensing potential collision. In this window, if no collision detected, use this random number as
/* Default antenna delay values for 64 MHz PRF. */
#define TX_ANT_DLY 16385
#define RX_ANT_DLY 16385
/* Frames used in the ranging process. */
// First two are frame control.
static uint8_t tx_poll_msg[] = { 0x41, 0x88, 0, 0xCA, 0xDE, 'W', 'A', 'V', 'E', 0x21, 1, 1, 1, 1};
static uint8_t rx_resp_msg[] = { 0x41, 0x88, 0, 0xCA, 0xDE, 'V', 'E', 'W', 'A', 0x10, 0x02, 0, 0, 1, 1, 1, 1 };
static uint8_t tx_final_msg[] = { 0x41, 0x88, 0, 0xCA, 0xDE, 'W', 'A', 'V', 'E', 0x23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1};
#define ALL_MSG_COMMON_LEN 17
/* Indexes to access some of the fields in the frames defined above. */
#define ALL_MSG_SN_IDX 2
#define FINAL_MSG_POLL_TX_TS_IDX 10
#define FINAL_MSG_RESP_RX_TS_IDX 14
#define FINAL_MSG_FINAL_TX_TS_IDX 18
/* 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];
/* 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;
/* Delay between frames, in UWB microseconds. See NOTE 4 below. */
/* This is the delay from the end of the frame transmission to the enable of the receiver, as programmed for the DW IC's wait for response feature. */
#define POLL_TX_TO_RESP_RX_DLY_UUS (300 + CPU_PROCESSING_TIME)
/* This is the delay from Frame RX timestamp to TX reply timestamp used for calculating/setting the DW IC's delayed TX function.
* This value is required to be larger than POLL_TX_TO_RESP_RX_DLY_UUS. Please see NOTE 4 for more details. */
#define RESP_RX_TO_FINAL_TX_DLY_UUS (300 + CPU_PROCESSING_TIME)
/* Receive response timeout. See NOTE 5 below. */
#define RESP_RX_TIMEOUT_UUS 300
/* Preamble timeout, in multiple of PAC size. See NOTE 7 below. */
#define PRE_TIMEOUT 5
/* Time-stamps of frames transmission/reception, expressed in device time units. */
static uint64_t poll_tx_ts;
static uint64_t resp_rx_ts;
static uint64_t final_tx_ts;
extern dwt_txconfig_t txconfig_options;
#define ID_LEN 2
static uint32_t seq = 0;
// Define the anchors ID array
#define NUM_ANCHOR 4
static uint8_t anchor_id[ID_LEN * NUM_ANCHOR] = {0x11, 0x11, 0x11, 0x12, 0x11, 0x13, 0x11, 0x14};
#define SENDER_ID_A 5
#define SENDER_ID_B 6
#define RECEIVER_ID_A 7
#define RECEIVER_ID_B 8
static int cnt = 0;
const nrf_drv_timer_t TIMER_LOCALIZATION = NRF_DRV_TIMER_INSTANCE(0); //Use Timer0
static uint8_t period_start = 0;
void timer_period_handler(nrf_timer_event_t event_type, void* p_context)
{
if (event_type == NRF_TIMER_EVENT_COMPARE0) // We are using Compare Channel 0
{
period_start = 1;
}
}
/*
So far, a full localization requring TWR with 4 anchors takes around 0.01 second
Thus, if we want two seperate slots suggesting no interference, the number of slots
should be <= 1/0.01 = 100. Because we only have 3 tags at most, we use 50 slots here.
The RNG will generate a number from 0 to 255 evenly. For a simple implementation, we use
rng / 5 to determine which slots it uses. If it's 255/5 = 51, we manually set it 50.
*/
#define RANDOM_BUFFER_SIZE 1
uint8_t rn[RANDOM_BUFFER_SIZE];
#define SLOT_NUM 51
int ds_twr_sender_init(void)
/*
This function is initiating the settup of IC and ensuring the IC
is in the correct status. Also, it sets up the delays and timeouts.
*/
{
// Codes below are initiating the IC to IDLE_RC status and checking its status
port_set_dw_ic_spi_fastrate();
reset_DWIC();
Sleep(2);
uint8_t self_id_up = (NRF_FICR->DEVICEID[1] & 0xff000000) >> 24;
uint8_t self_id_lo = (NRF_FICR->DEVICEID[1] & 0x00ff0000)>> 16;
dwt_probe((struct dwt_probe_s *)&dw3000_probe_interf);
while (!dwt_checkidlerc());
if (dwt_initialise(DWT_DW_INIT) == DWT_ERROR)
{
while (1);
}
// Configure the communication channel
if (dwt_configure(&config))
{
while (1);
}
// Configure the transmission such as the power
dwt_configuretxrf(&txconfig_options);
// Codes below are for delay setting
dwt_setrxantennadelay(RX_ANT_DLY);
dwt_settxantennadelay(TX_ANT_DLY);
dwt_setrxaftertxdelay(POLL_TX_TO_RESP_RX_DLY_UUS);
// Set up the timeout
dwt_setrxtimeout(RESP_RX_TIMEOUT_UUS);
dwt_setpreambledetecttimeout(PRE_TIMEOUT);
// Set up the Low Noise Amplifier (receiving) and Power Amplifier (transmitting)
dwt_setlnapamode(DWT_LNA_ENABLE | DWT_PA_ENABLE);
tx_poll_msg[SENDER_ID_A] = self_id_up;
tx_poll_msg[SENDER_ID_B] = self_id_lo;
rx_resp_msg[RECEIVER_ID_A] = self_id_up;
rx_resp_msg[RECEIVER_ID_B] = self_id_lo;
tx_final_msg[SENDER_ID_A] = self_id_up;
tx_final_msg[SENDER_ID_B] = self_id_lo;
printf("0X%X \n", self_id_up);
return 0;
}
int ds_twr_rng_sender_verfify(uint8_t* rx_buffer)
// It's to verfiy if the good frame received is the ranging frame we expect
{
if (memcmp(rx_buffer, rx_resp_msg, ALL_MSG_COMMON_LEN) == 0)
{
return 1;
}
else{
return 0;
}
}
bool valid_time_indicator = false;
uint32_t ds_twr_generating_starting_time (void){
uint32_t delay_time, irq_mask;
uint8_t slot_num;
//Set rx timeout to collision window size temporarily.
dwt_setrxtimeout(COLLISION_SENSING_DELAY_US);
while (valid_time_indicator == false)
{
nrf_drv_rng_rand(rn, RANDOM_BUFFER_SIZE);
slot_num = *rn / 5;
if (slot_num == 51){ slot_num = 50;}
delay_time = (slot_num) * 990 / SLOT_NUM;
irq_mask = DWT_INT_RXFCG_BIT_MASK | SYS_STATUS_ALL_RX_TO | SYS_STATUS_ALL_RX_ERR;
dwt_rxenable(DWT_START_RX_IMMEDIATE);
while(!((status_reg = dwt_readsysstatuslo()) & irq_mask)); // keep reading and checking the system status register
if (status_reg & SYS_STATUS_ALL_RX_TO) // if it's timeout.
{
printf("IT's timeout!\n");
valid_time_indicator = true;
dwt_writesysstatuslo(SYS_STATUS_ALL_RX_TO);
}
else
{
printf("COLLISION or ERR\n");
valid_time_indicator = true;
dwt_writesysstatuslo(DWT_INT_RXFCG_BIT_MASK | SYS_STATUS_ALL_RX_ERR);
}
}
dwt_setrxtimeout(RESP_RX_TIMEOUT_UUS);
printf("DELAYTIME: %u \n", delay_time);
return delay_time;
}
void ds_twr_sender_proc(void)
{
uint32_t delay;
while(1){
while(period_start)
{
/*if (cnt == 0){
nrf_drv_rng_rand(rn, RANDOM_BUFFER_SIZE);
printf("RNG: %u \n", *rn);
uint8_t slot_num = *rn / 5;
//printf("RNG/5 %u \n", slot_num);
if (slot_num == 51){ slot_num = 50;}
uint32_t delay_time = (slot_num) * 990 / SLOT_NUM; //Convert the delay to ms
//printf("The Delay Time this round is: %u", delay_time);
//printf("\n");
nrf_delay_ms(delay_time); //Delay the delay time and then start localization
}*/
if (valid_time_indicator)
{
if (cnt == 0){
nrf_delay_ms(delay);
}
}
else
{
delay = ds_twr_generating_starting_time();
}
//Write the seq into the frames
tx_poll_msg[13] = (uint8_t)(seq & 0xFF);
tx_poll_msg[12] = (uint8_t)((seq >> 8) & 0xFF);
tx_poll_msg[11] = (uint8_t)((seq >> 16) & 0xFF);
tx_poll_msg[10] = (uint8_t)((seq >> 24) & 0xFF);
rx_resp_msg[16] = (uint8_t)(seq & 0xFF);
rx_resp_msg[15] = (uint8_t)((seq >> 8) & 0xFF);
rx_resp_msg[14] = (uint8_t)((seq >> 16) & 0xFF);
rx_resp_msg[13] = (uint8_t)((seq >> 24) & 0xFF);
tx_final_msg[25] = (uint8_t)(seq & 0xFF);
tx_final_msg[24] = (uint8_t)((seq >> 8) & 0xFF);
tx_final_msg[23] = (uint8_t)((seq >> 16) & 0xFF);
tx_final_msg[22] = (uint8_t)((seq >> 24) & 0xFF);
printf("SEQ: %u \n", seq);
printf("SEQ_DEVIDE: %u, %u, %u, %u \n", tx_poll_msg[10], tx_poll_msg[11], tx_poll_msg[12], tx_poll_msg[13]);
//printf("%d vs %d\n", sizeof(tx_poll_msg), strlen(tx_poll_msg));
/*for (int i =0; i< sizeof(tx_poll_msg); i++){
printf(" %x", tx_poll_msg[i]);
}
printf("\n len: %d \n", sizeof(tx_poll_msg) );*/
//Starting looping the tags' ID
tx_poll_msg[RECEIVER_ID_A] = anchor_id[2 * cnt];
tx_poll_msg[RECEIVER_ID_B] = anchor_id[2 * cnt + 1];
printf("1 \n");
rx_resp_msg[SENDER_ID_A] = anchor_id[2 * cnt];
rx_resp_msg[SENDER_ID_B] = anchor_id[2 * cnt + 1];
tx_final_msg[RECEIVER_ID_A] = anchor_id[2 * cnt];
tx_final_msg[RECEIVER_ID_B] = anchor_id[2 * cnt + 1];
cnt ++;
if (cnt == NUM_ANCHOR){
//printf("PERIOD_FINISH\n");
period_start = 0; // if it finished a cycle, flip the flag and stop localization until next period
seq ++;
//Sleep(PERIOD_DELAY_MS);
}
cnt %= NUM_ANCHOR;
dwt_writetxdata(sizeof(tx_poll_msg), tx_poll_msg, 0);
// The length is the len(frame) + FCS_LEN (CRC bytes). Offset is 0 and ranging = 1.
dwt_writetxfctrl(sizeof(tx_poll_msg) + FCS_LEN, 0, 1);
dwt_starttx(DWT_START_TX_IMMEDIATE | DWT_RESPONSE_EXPECTED);
while(!(dwt_readsysstatuslo() & DWT_INT_TXFRS_BIT_MASK));
printf("2 \n");
dwt_writesysstatuslo(DWT_INT_TXFRS_BIT_MASK);
// this mask contains three conditions: Good receiving, all kinds of receiving timeout and all kinds of receiving errors
uint32_t irq_mask = DWT_INT_RXFCG_BIT_MASK | SYS_STATUS_ALL_RX_TO | SYS_STATUS_ALL_RX_ERR;
while(!((status_reg = dwt_readsysstatuslo()) & irq_mask)); // keep reading and checking the system status register
if (status_reg & DWT_INT_RXFCG_BIT_MASK) // if a good frame is received
{
printf("3 \n");
// Reset the receiving good frame bit
dwt_writesysstatuslo(DWT_INT_RXFCG_BIT_MASK);
uint16_t len = dwt_getframelength();
if (len <= RX_BUF_LEN)
{
dwt_readrxdata(rx_buffer, len, 0);
}
//printf("RX_BUFFER: %u\n", *rx_buffer);
rx_buffer[2] = 0;
if (ds_twr_rng_sender_verfify(rx_buffer))
{ // All timestamps here are in DWT_Timeunit but not in real-world seconds
// The timestamps are 40 bits stored in 64 bits uint
printf("4 \n");
poll_tx_ts = get_tx_timestamp_u64();
resp_rx_ts = get_rx_timestamp_u64();
uint32_t final_tx_time = (resp_rx_ts + (RESP_RX_TO_FINAL_TX_DLY_UUS * UUS_TO_DWT_TIME)) >> 8; // Get the higher 32 bits
dwt_setdelayedtrxtime(final_tx_time);
// But the delayed tx_time has resolution of 512 units which means the lower 9 bits should be 0 (though the input of dwt_setdelayedtrxtime is 32 bits, only 31 bits are valid because of the resolution)
final_tx_ts = (((uint64_t)(final_tx_time & 0xFFFFFFFEUL)) << 8) + TX_ANT_DLY;
// This function extracts the lower-32-bits of the timestamp and saves it to the right position
// ? What if the timestamps are just at carrying? Due to this is a rare case, we can set a condition and abandon it.
final_msg_set_ts(&tx_final_msg[FINAL_MSG_POLL_TX_TS_IDX], poll_tx_ts);
final_msg_set_ts(&tx_final_msg[FINAL_MSG_RESP_RX_TS_IDX], resp_rx_ts);
final_msg_set_ts(&tx_final_msg[FINAL_MSG_FINAL_TX_TS_IDX], final_tx_ts);
dwt_writetxdata(sizeof(tx_final_msg), tx_final_msg, 0);
dwt_writetxfctrl(sizeof(tx_final_msg) + FCS_LEN, 0, 1);
int txcheck = dwt_starttx(DWT_START_TX_DELAYED); // Delay sending
if (txcheck == DWT_SUCCESS)
{
while (! (dwt_readsysstatuslo() & DWT_INT_TXFRS_BIT_MASK));
printf("5 \n");
dwt_writesysstatuslo(DWT_INT_TXFRS_BIT_MASK);
//cnt ++;
//cnt %= NUM_ANCHOR;
}
}
else{
valid_time_indicator = false;
}
}
else{
dwt_writesysstatuslo(SYS_STATUS_ALL_RX_TO | SYS_STATUS_ALL_RX_ERR);
}
nrf_delay_us(RNG_DELAY_US);
}
}
}
#endif
void tag(){
bsp_board_init(BSP_INIT_LEDS | BSP_INIT_BUTTONS);
gpio_init();
nrf52840_dk_spi_init();
dw_irq_init();
nrf_delay_ms(2);
printf("DONE");
//Timer Setup
nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;
nrf_drv_timer_init(&TIMER_LOCALIZATION, &timer_cfg, timer_period_handler);
//Caution: Computing ticks should be after timer_init because it requires the
//timer configed (timer_cfg) so that the related parameters could be fixed.
uint32_t time_ms = PERIOD_DELAY_MS;
uint32_t time_ticks;
time_ticks = nrf_drv_timer_ms_to_ticks(&TIMER_LOCALIZATION, time_ms);
printf("%u", time_ticks);
nrf_drv_timer_extended_compare(&TIMER_LOCALIZATION, NRF_TIMER_CC_CHANNEL0, time_ticks, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, true);
nrf_drv_timer_enable(&TIMER_LOCALIZATION);
//RNG Setup
uint32_t err_code;
nrf_drv_rng_init(NULL);
nrf_delay_ms(2);
ds_twr_sender_init();
ds_twr_sender_proc();
}