Ultra Wide Band One Way Ranging Issues

Hello!

I am new to UWB technology and am somewhat familiar with the STM32FXX microcontroller family. I am using a STM32F205RET7 board with the DW1000 chip to implement a one way ranging protocol. I am using CubeMX to initialize my peripherals and the IDE included. I am using only one anchor and tag for now, but I would eventually like to have a configurable number of anchors in the system. The tag acts as the “initiator” which sends an initial message to the anchor which acts as a “responder”, which responds to the initial message by sending a pre-determined response message back to the initiator. The tag would then use the timestamps of when each message is sent and received to calculate the time of flight it takes to communicate between the two components, and from there the distance between them. I am running into some issues confirming whether the initial message is received, however.

  1. This is how I am checking that the message is done being sent by the initiator:
    .
    .
    (rest of code)
    .
    .

dwt_starttx(DWT_START_TX_IMMEDIATE | DWT_RESPONSE_EXPECTED); // start transmission

    while(1)
    {
    	uint32_t status = dwt_read32bitreg(SYS_STATUS_ID);
    	if ((status & SYS_STATUS_TXFRS) != 0) // check if the TXFRS bit is set in the status register
    	{
    		HAL_GPIO_TogglePin(GPIOC, LED_GRN_Pin); // toggle the green LED
    		RedLED_off();
    		break;
    	}
    }

dwt_rxenable(DWT_START_RX_IMMEDIATE); // enable receptions immediately following end of transmission

status_reg = dwt_read32bitreg(SYS_STATUS_ID); // save a copy of the status register

while (!((status_reg = dwt_read32bitreg(SYS_STATUS_ID)) & (SYS_STATUS_RXFCG | SYS_STATUS_ALL_RX_TO | SYS_STATUS_ALL_RX_ERR)))
{}; // we assume that the transmission is achieved correctly, poll for reception of a frame or error/timeout
.
.
(rest of code)
.
.

  1. Here is the beginning of the responder side of my code:
    while (1) // loop forever responding to ranging requests
    {

     dwt_setrxtimeout(0); //  clear reception timeout to start next ranging process
    
     dwt_rxenable(DWT_START_RX_IMMEDIATE); //  activate reception immediately
    
     status_reg = dwt_read32bitreg(SYS_STATUS_ID);  // save a copy of the status register
    
     while (!((status_reg) & (SYS_STATUS_RXFCG | SYS_STATUS_ALL_RX_ERR | SYS_STATUS_ALL_RX_TO)))
     {}; // poll for reception of a frame or error/timeout
    

.
.
(rest of code)
.
.

Where I’m running into issues is that when I run my code for the responder, it will “get stuck” somewhere, not recognize a message and set the RXPTO bit (preamble detection timeout, because no preamble was detected being received), and only have the red LED stay on, which is not corresponding to my code. If I go into debug mode and step through the responder code to where it should be responding to the initial message. it correctly recognizes a message, sets the RXFCG bit to indicate reception is complete, and reads it into the local buffer. This behavior does not happen when I just hit run. How may I fix this issue?

If any other context is needed, please let me know. Thank you!!

If things work stepping through but not when you hit then 99% of the time the issue is with timings. The transmitter is transmitting before the receiver is ready, the receiver is timing out and giving up before the transmitter starts etc… Or possibly you’ve got an invalid combination of delays and wait times. If the unit sends the initial message but then has a receive timeout set that is the same or less than the receivers fixed delay then things will never work.

While you can try to code things so this never happens it’s normally easier and more reliable to code them to cope with it.
Transmitter sends a message and then doesn’t get a reply within the expected time? Send the message again. Receiver times out waiting for the initial message? Re-arm the receive process.

Tow other notes - There is an option to make the device automatically enter receive mode after completing a transmission, this can simplify the code in some situations.
The system you describe is normally called single sided two way ranging. One way ranging would be if only one device/set of devices transmitted.

Update:

Thanks for the suggestion Andy, and the clarification on the type of ranging I’m trying to achieve. Here is my error checking code for the timeouts on the responder side:
.
.
(rest of code)
.
.
while(1)
{
dwt_setpreambledetecttimeout(PRE_TIMEOUT); // I moved this line to within the polling loop to attempt to reset the preamble detection timer every time we iterate through without a message being received. That is ultimately what I trying to achieve because of the flag that is getting set plus your suggestion. Before, it was being set before the infinite loop I have that is responding to ranging requests.
.
.
(rest of code)
.
.
while (!((status_reg) & (SYS_STATUS_RXFCG | SYS_STATUS_ALL_RX_ERR | SYS_STATUS_ALL_RX_TO)))
{};
if (status_reg & SYS_STATUS_ALL_RX_TO)
{
status_reg = dwt_read32bitreg(SYS_STATUS_ID); // save a copy to examine in debugger
.
.
(rest of code)
.
.
if (status_reg & SYS_STATUS_RXPTO)
{
status_reg &= ~SYS_STATUS_RXPTO; // clear preamble detection flag
status_reg = dwt_read32bitreg(SYS_STATUS_ID); // save a copy to examine in debugger
}
.
.
(rest of code)
.
.
After this point, it loops correctly back to the beginning of the infinite while if a message hasn’t been received, but obviously I’d like to actually respond to a message. Like stated previously, I’ve confirmed that my initiator is sending a message at a regular interval by checking if the TXFRS bit is set, which corresponds to the completion of a frame transmission. I haven’t checked the corresponding pin using an oscope, but I suppose I could do that to further confirm I’m getting the behavior I’m expecting from the initiator.

Right now, I’m still running into the same problem with the responder where it gets stuck when I just hit run, but I can see the message being correctly received and responded to if I just step through the code in the debugger.

Also, I was reading about the dwt_setpreambledetecttimeout(); function in the DW1000 API catalouge, and I found out you can avoid needing to set a timeout at all by just passing that function a 0 instead. I tried that by setting PRE_TIMEOUT to 0 and letting it run, and I’m still getting the same behavior as before both when I just hit run and when I use the debugger. I’m sort of stuck now, not quite sure where to go. It seems that there is still a timing issue to me. Any further suggestions?? Thanks again!!

  1. when posting code please use the preformatted text option, it keeps the formatting readable.

while (!((status_reg) & (SYS_STATUS_RXFCG | SYS_STATUS_ALL_RX_ERR |SYS_STATUS_ALL_RX_TO)))
{};

Since the value of status_reg doesn’t change anywhere in this code this is either going to exit instantly or loop forever. You need to re-read the status register each time around the loop.