Transmit 3 own double variables in poll message

Hi,

I would like to transmit 3 double vars in the poll message from the initiator to a responder.
in the initiator i do:
memcpy(&tx_poll_msg2[12],&filtered1,MYDATA_LEN);
memcpy(&tx_poll_msg2[20],&filtered2,MYDATA_LEN);
memcpy(&tx_poll_msg2[28],&Angle,MYDATA_LEN);

and in the responder i need to get the bytes and put them in doubles for use:
double d = 0;
unsigned char buf[sizeof d] = {0};
buf[0] = rx_buffer[12];
buf[1] = rx_buffer[13];
buf[2] = rx_buffer[14];
buf[3] = rx_buffer[15];
buf[4] = rx_buffer[16];
buf[5] = rx_buffer[17];
buf[6] = rx_buffer[18];
buf[7] = rx_buffer[19];

  memcpy(&d, buf, sizeof d);

This will give me the first variable in double format.

My question where and how can i put this in the responder program without affecting time critical data exchange between the devices?

Any suggestions?

Thanks in advance

Not an answer to you question but you can speed up your code by using casts to pointers rather than calls to memcpy:
Tx:
*(double *)(tx_poll_msg2+12)=filtered1;
*(double *)(tx_poll_msg2+20)=filtered2;
*(double *)(tx_poll_msg2+28)=Angle;
Rx:
double d = *(double *)(rx_buffer+12);

In both cases the time saving won’t be huge but it will help if you are that worried about timing impact.

One thing to watch out for, on ARM cpus with floating point support floats and doubles must be 32 bit aligned. i.e. double d = *(double *)(rx_buffer+4); will work but double d = *(double *)(rx_buffer+5); would generate a hard fault. Since 12,20 and 28 are all multiples of 4 you are safe in this instance but it is something to watch out for.

1 Like

Thanks Andy! i’m new to C# so very nice you shared me your example. Just tried it and up and running!

I have now the desired distances available in the responder.

That was c or c++, which is what I assumed you were using since your code and the memcpy function and the rest of your code was c.

c# is very different, it would be:
byte [] outputBytes = BitConverter.GetBytes(filtered1);
Array.Copy(tx_poll_msg2,12,outputBytes ,0,8);

and

double d = BitConverter.ToDouble(rx_buffer,12)

but c# isn’t normally used for embeded systems, it’s too slow and too high in memory usage.

Sorry, my mistake…lack of knowledge in programming:(
Main goal is to send 2 distances and 1 angle to 1 responder. Perhaps i could also scale and round the values to cm and degrees like 0-500cm and -90-90 degrees. this saves some bytes in the payload…

Thanks for your help Andy!

Casting to scaled integers is often a good solution if you have a known range. If nothing else using floats rather than doubles will halve the data size and still give you mm resolution for distances of over 1 km. Using doubles is overkill.

A uint16_t in cm will give you 320m of range, more than enough range if you don’t mind the loss of resolution.
Keep in mind you don’t need to use neat numbers. e.g. if you were to use units of 1/2 cm rather than 1 cm then you get 5 mm resolution and ranges up to ~160 m. It’s a little unintuitive but you may as well maximize the available resolution.

Or you could use a uint32_t and have the ranges in mm or even 10ths of a mm. This doesn’t give any data size saving over a float but will be a lot faster for any calculations.

A quick google gives an integer add as 1 cycle, float add as 34 cycles and double add as 59 cycles. That’s for a different Arm core so those numbers aren’t exact but gives you an idea of the performance hit using floating point unless you have a part with hardware FPU. Even when you do doubles are often a performance hit over floats and should be avoided if you don’t need them.

One other trick for programming in c if you need performance:

float range = 100.09;
// simple scale and convert to int, fastest but has rounding issues
int x = range * 10 ; // x = 1000.9 truncated to an integer = 1000
// add 0.5 after scale to give correct rounding
int y = range * 10 + 0.5; // y = 1001.4 = 1001;
// slightly faster version
int z = range * 10 + 0.5f;

In theory y and z should be identical but unless the compiler is smart z will be faster.
The constant 0.5 is a double and anything plus a double is calculated as a double. So for y the range * 10 is calculated as a float and then converted to a double before adding the 0.5. For z we explicitly say 0.5 is a float and so the whole calculation is done as a float.

1 Like

Thanks AndyA. This makes sense and gets me going.

Do you also know where i can find info about how to read GPIO13 in the DWM1001 module?

I got it working.

I used the following code to read GPIO13.
In Main.c
nrf_gpio_cfg_input(DW1000_IDX_13, NRF_GPIO_PIN_PULLUP);

In ss_resp_run(void)
bool input13 = nrf_gpio_pin_read(DW1000_IDX_13)

Just that simple…