cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
Highlighted
Explorer
Explorer
11,155 Views
Registered: ‎08-26-2014

Working with double precision floating-point on the ARM

Jump to solution
Hello, I am programming an application to work with double precision floating-point coded in C that will be ran on the ARM processor. The problem is that I need to send back to the computer all the results via UART. How does the Zynq stores a 64bit-length word on memory? How should I send this data through the UART if it has to be sent byte by byte? I had found a solution but it seems it does not work as expected: double data = -1.234; unsigned char *chptr, x; chptr = (unsigned char *) &data; for(x=0;x<8;x++) { xil_printf(*chptr++); } I had also found that people converts the value to a string and then send it, but like I will be using large amunts of data, I think it is not an efficient solution. Does anyone know how to deal with this? Many thanks.
0 Kudos
1 Solution

Accepted Solutions
Highlighted
Explorer
Explorer
20,139 Views
Registered: ‎08-26-2014

Many thanks @muzaffer! Now it is working!

 

I was not aware that the pointers always point to bytes, and depending on the type of its definition, they jump every 1, 2, 4, or 8 bytes according to its definition as char, short, int, or long respectively.

 

I was trying is to send an stack of double precision floating-point data (64bits or 8 bytes) to Matlab's Simulink. I was first having problems in sending the data from the Zynq and then figuring out how to configure the Serial Receive block to get all the data from the Zynq. So now it is working.

 

I post here all the info needed to get this working.

 

On Simulink, the Serial Configuration block has to be:

 

Baud rate: 115200

Data bits: 8

Parity: none

Stop bits: 1

Byte order: LittleEndian

Flow control: none

Timeout: 10

 

And then the Serial Receive block:

 

Header: [empty]

Terminator: none

Data size: 1

Data type: double

 

And the code to be programmed on the Zynq can be this:

 

 

double stack[] = {1.0, 1.1, -1.1, 100000000};
char *chptr, x;
	
chptr = (char*)&stack;
	
for(x=0;x<8*sizeof(f);x++)
   XUartPs_SendByte(STDOUT_BASEADDRESS, *chptr++);

 

 

Many thanks for your help!

 

Cerilet

View solution in original post

0 Kudos
7 Replies
Highlighted
11,142 Views
Registered: ‎03-27-2014

yes it has to be sent byte per byte.
double precision represents data on 64bit, my guess is you could do something like

 

double f = 0.5;
uint64_t *temp, bytes_sent;
char *_to_send;

temp = (uint64_t*)&temp; // binary value for 0.5
_to_send = temp;

for( k=0; k < 64/8; k++ )
   _bytes_sent = send_uart( _to_send, sizeof( char )); // send one byte
   _to_send += _bytes_sent; // one byte offset

you can do that with an array too, because your are always incrementing by one byte(8 bit) over 64

gw.
Embedded Systems, DSP, cyber
Highlighted
Teacher
Teacher
11,119 Views
Registered: ‎03-31-2012
when you say " it does not work as expected" what do you mean? you tried to send over uart and what happened?
If you are just talking about the xil_printf(*chptr++); line this is expected not to work. The first parameter of xil_printf is a pointer to the format string. You need something like: xil_printf("%c", *chptr++);
- Please mark the Answer as "Accept as solution" if information provided is helpful.
Give Kudos to a post which you think is helpful and reply oriented.
0 Kudos
Highlighted
Explorer
Explorer
11,085 Views
Registered: ‎08-26-2014

First of all, thanks for your quick reply.

 

To @guillaumebres: I do not understand what send_uart return to then make the assignation _to_send += _bytes_sent.

 

 

Apart from that, there is a mistake in here:

 

temp = (uint64_t*)&f;

 

To @muzaffer: When I said it does not work as expected is that I cannot reconstruct the data on the receiver's end.

 

Actually, I do not know how that instruction works (*chptr++). I was making some tests trying to figure out how the data is send and how an 8bit pointer increments if the system is 32bit but I could not.

 

If the memory on the Zynq is 32bit long, the pointer should point to a 32bit-length address, therefore, how can I point to one byte at a time? Moreover, how to send the data in the proper format to be recognized on the receiver's end: %c, %x, %d...?

 

Here the code I posted before, but now formatted and modified according to @muzaffer's suggestions:

 

double data = -1.234;
unsigned char *chptr, x;

chptr = (unsigned char *) &data;

for(x=0;x<8;x++)
{
   xil_printf("%c",*chptr++);
}

Many thanks to both.

 

Cerilet

 

0 Kudos
Highlighted
Teacher
Teacher
11,081 Views
Registered: ‎03-31-2012
A double is 8 bytes long. You take its address and cast it to a char*. Now you can increment it one byte at a time. So (char*)&data points to lsb of the data (in intel x86 architecture cpus) and chptr+7 points to msb. If you transmit them in that order, you can reconstruct as
uint64_t rx = b7*(1<<56) + b6*(1<<48) + b5*(1<<40) + b4*(1<<32) + b3*(1<<24) + b2*(1<<16) + b1*(1<<8) + b0;
double drx = *(double*)&rx;
assuming b0 is the first transmitted and received byte.
- Please mark the Answer as "Accept as solution" if information provided is helpful.
Give Kudos to a post which you think is helpful and reply oriented.
Highlighted
Explorer
Explorer
20,140 Views
Registered: ‎08-26-2014

Many thanks @muzaffer! Now it is working!

 

I was not aware that the pointers always point to bytes, and depending on the type of its definition, they jump every 1, 2, 4, or 8 bytes according to its definition as char, short, int, or long respectively.

 

I was trying is to send an stack of double precision floating-point data (64bits or 8 bytes) to Matlab's Simulink. I was first having problems in sending the data from the Zynq and then figuring out how to configure the Serial Receive block to get all the data from the Zynq. So now it is working.

 

I post here all the info needed to get this working.

 

On Simulink, the Serial Configuration block has to be:

 

Baud rate: 115200

Data bits: 8

Parity: none

Stop bits: 1

Byte order: LittleEndian

Flow control: none

Timeout: 10

 

And then the Serial Receive block:

 

Header: [empty]

Terminator: none

Data size: 1

Data type: double

 

And the code to be programmed on the Zynq can be this:

 

 

double stack[] = {1.0, 1.1, -1.1, 100000000};
char *chptr, x;
	
chptr = (char*)&stack;
	
for(x=0;x<8*sizeof(f);x++)
   XUartPs_SendByte(STDOUT_BASEADDRESS, *chptr++);

 

 

Many thanks for your help!

 

Cerilet

View solution in original post

0 Kudos
Highlighted
Visitor
Visitor
548 Views
Registered: ‎07-17-2017

Thank you for the solution. 

for(x=0;x<8*sizeof(f);x++)

But, I don't understand. what's the f in this block.?

0 Kudos
Highlighted
Visitor
Visitor
95 Views
Registered: ‎11-17-2020

It's a double in @guillaumebres 's answer:

double f = 0.5;
uint64_t *temp, bytes_sent;
char *_to_send;

temp = (uint64_t*)&temp; // binary value for 0.5
_to_send = temp;

for( k=0; k < 64/8; k++ )
   _bytes_sent = send_uart( _to_send, sizeof( char )); // send one byte
   _to_send += _bytes_sent; // one byte offset
0 Kudos