How to receive multiple messages in a TDOA

If you say it works up to 60 ms but goes wrong for longer times.
A 32 bit time would overflow at 2^32 / (128*499.2e6) = 67 ms.

I suspect that you still have a 32 bit overflow issue somewhere.

this should not happen with delay 60ms as DW1000 has overflow when exceeds ~17s, I think your code has some problem when using sprintf.

you can try:

    uint64_t last_dw_systime;
    while (1)
    {
      uint64_t timestamp = get_system_timestamp_u64();
      char dataseq[50];
      sprintf((char*)&dataseq, "current: %lu \r\n", timestamp);
      port_tx_msg(dataseq, strlen(dataseq));
      uint64_t Dt = timestamp - last_dw_systime;
      sprintf((char*)&dataseq, "diff: %08x%08x\r\n", Dt >> 32, Dt);
      port_tx_msg(dataseq, strlen(dataseq));
      last_dw_systime = timestamp;
      HAL_Delay(60);
    };

@chxt sorry I don’t really know about sprintf
here is the code result for delay 60ms , I have add space between

current: 807751680 
diff: 00000000 00000000 
current: 656876032 
diff: 00000000 00000000 
current: 505660928 
diff: 00000000 00000000 

result for delay 70ms

current: 1314433536 
diff: 00000001 00000000 
current: 1803096064 
diff: 00000001 00000000 
current: 2291286528 
diff: 00000001 00000000 
current: 2779574272 
diff: 00000001 00000000 

so there is the problem with sprintf?

also the get_system_timestamp_u64 function is below

static uint64_t get_system_timestamp_u64(void)
{
    uint8_t ts_tab[5];
    uint64_t ts = 0;
    int i;
    dwt_readsystime(ts_tab);
    for (i = 4; i >= 0; i--)
    {
        ts <<= 8;
        ts |= ts_tab[i];
    }
    return ts;
}

sorry,

should be:

      sprintf((char*)&dataseq, "diff: %08lx%08lx\r\n", Dt >> 32, Dt);

I forgot the l flag, could you give it a try

thanks @chxt , but it seems to be the same

current: 3396481536 
diff: 0000000100000000 
current: 3882179584 
diff: 0000000100000000 
current: 73342464 
diff: 0000000100000000 
current: 495520768 
diff: 0000000100000000 

I’m sure it’s the problem from sprintf.

and maybe this will work (explicit use of hi/lo part of the timestamp):

    uint64_t last_dw_systime;
    while (1)
    {
      uint64_t timestamp = get_system_timestamp_u64();
      char dataseq[50];
      sprintf((char*)&dataseq, "current: %lu \r\n", timestamp);
      port_tx_msg(dataseq, strlen(dataseq));
      uint64_t Dt = timestamp - last_dw_systime;
      uint32_t Dt_hi = Dt >> 32;
      uint32_t Dt_lo = Dt;
      sprintf((char*)&dataseq, "diff: %08lx%08lx\r\n", Dt_hi, Dt_lo);
      port_tx_msg(dataseq, strlen(dataseq));
      last_dw_systime = timestamp;
      HAL_Delay(60);
    };

@AndyA @chxt

    uint32_t last_lo = 0;
    uint8_t last_hi = 0;
    while (1)
    {
      uint8_t dt[5];
      dwt_readsystime(dt);

      uint32_t lo = 0;
      uint8_t hi = 0;

      memcpy(&lo, dt, 4);
      hi = dt[4] ;

      char dataseq[50];
      sprintf((char*)&dataseq, "current: hi-> %d lo %lu \r\n", hi, lo);
      port_tx_msg(dataseq, strlen(dataseq));
      sprintf((char*)&dataseq, "diff: hi-> %d lo %lu \r\n", hi - last_hi, lo - last_lo);
      port_tx_msg(dataseq, strlen(dataseq));

      last_lo = lo;
      last_hi = hi;
      HAL_Delay(70);
    };

output

current: hi-> 77 lo 3835064832 
diff: hi-> 1 lo 549956608 
current: hi-> 79 lo 89716736 
diff: hi-> 2 lo 549619200 
current: hi-> 80 lo 638417920 
diff: hi-> 1 lo 548701184 
current: hi-> 81 lo 1187227648 
diff: hi-> 1 lo 548809728 
current: hi-> 82 lo 1736324608 
diff: hi-> 1 lo 549096960 
current: hi-> 83 lo 2284209664 
diff: hi-> 1 lo 547885056 
current: hi-> 84 lo 2832536064 
diff: hi-> 1 lo 548326400 
current: hi-> 85 lo 3382010880 
diff: hi-> 1 lo 549474816 
current: hi-> 86 lo 3931201536 
diff: hi-> 1 lo 549190656 
current: hi-> 88 lo 184390656 
diff: hi-> 2 lo 548156416

In [249]: (1* 65536 * 65536 + 548156416) * DWT_TIME_UNITS
Out[249]: 0.07579508012820513


use above code and confirmed the overflow problem

@chxt @AndyA there is some problems with DWM1004C’s stm32L0 handling uint64_t, I just avoid using uint64_t now

Now I have problem calculate the TDoA time, cause the when the Anchor send blink frame in the same time, the tag will loose messages, so I set fix delay time to Anchor with times of its anchor id, so when I look into the api document, it shows 0x17CDC00 is for adding 100ms, but
0x17CDC00 * 512/(499.2e6*128) is actually 0.2, so is the example wrong?

In [350]: 0x17CDC00 * 512/(499.2e6*128)
Out[350]: 0.2


Nowhere in the documentation does it say that the start time register is in units of 512/(4992.6e6*128) seconds (~8ns).

It says that since the least significant bit of the register is ignored that available the resolution becomes ~8ns. That would indicate that the actual units of the register are half of that size.

Or to look at it a different way the native time units of the DW1000 are (1/499.2e6 * 128) to 40 bit resolution. This is the high 32 bits of that 40 bit time which makes the units 2^8 * (1/499.2e6 * 128) seconds

@AndyA When I compare the time difference half of that delay uint make the data reasonable, I use same length cable to connect Anchor together and passing 5Hz signal to Anchor’stm32 gpio as interrupt, when interrupt trigger read dw1000 system time and set blink frame tx delay, when I put the anchor close and the distance difference should under 10cm, but in the tag is more than 30m, So I don’t know which part I raise the error

30 m of range error represents around 100 ns of time error.
From your description it sounds like you’re using the processor to set the zero point.
What’s the interrupt response time of your processor? For STM32 processors it’s normally measured in the 100’s of nanoseconds.

If you want any sort of accuracy you can’t have a processor in the loop for any of the timing critical parts of the system.

@AndyA there is no code running in Anchor’s stm32f103 main loop, and is there the processor time should be same with each Anchor, so it can be minus in time difference?

If you want any sort of accuracy you can’t have a processor in the loop for any of the timing critical parts of the system.

It doesn’t matter what the main loop is doing. It doesn’t matter if it’s the same processor running the same code. It doesn’t matter if it’s the highest priority interrupt there is. It doesn’t matter how fast the processor is.

If you had processor that was running at 2 GHz and responded to the interrupt instantly in a completely deterministic way there would still be a +/- 1/ (2 GHz) = 500ps = 15 cm variability between two systems due to the phase of the CPU clock.
So even with a far faster and unrealistically deterministic CPU the CPU would still be the largest source of error in the system.

If you want to synchronize the clocks between two DW1000s then you need to do it without having a processor in the loop.

@AndyA How cloud I reduce the processor in loop, since I have to control dw1000 via spi interface, or how to get the processor clock offset

You can control it over SPI with a processor. You just can’t use the processor for any timing critical parts of the clock synchronization routine.
You set up the registers using the processor but the actual synchronization must be done using the sync pin which needs to be controlled by hardware not by a CPU IO pin.