This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
char chunkdata[2] = {0}; uint16_t array_read[20] = {...};//initialized with some values float32_t var; chunkdata[0] = array_read[OFFSET] + (array_read[OFFSET+1] << 8); chunkdata[1] = array_read[OFFSET+2] + (array_read[OFFSET+3] << 8); var = *(float_t *)(&chunkdata[0]);
In the above code, the value of var is correct only if &chunkdata[0] has even value (chunk data is even aligned). But that depends on chance . If odd aligned address is supplied , then value of var is wrong. C28x decrements the address and then combines the value. __align() doesn't work for local variables according to compiler, so using it didn't help.
I want to split float into 4 8-bit chunks and join 4 8-bit chunks into float for EEPROM and CAN communication purposes. How to do it robustly? Also MISRA C compliance check is planned later. I am starting this post because I had marked previous post as resolved and now I can't undo it.
Hi Arpan,
I just closed your previous post to avoid multiple posts of similar issue. Please continue posting here. After your fix from the other thread, can you share the MISRA C violation?
Thanks,
Joseph
As an update to the thread, the following code solved the alignment issues and is working as expected:
float fvar; char * chunkdata; chunkdata = (char *)&fvar; uint16_t array_read[20] = {...};//initialized with some values float32_t var; chunkdata[0] = array_read[OFFSET] + (array_read[OFFSET+1] << 8); chunkdata[1] = array_read[OFFSET+2] + (array_read[OFFSET+3] << 8); var = *(float_t *)(&chunkdata[0]);
But it is violating MISRA guidelines. To test for MISRA, I created a separate CCS project with just main.c, which is as follows
/* */ /** * main.c */ #include <stdint.h> void main(void); void main(void) { float fvar; char * chunkdata; chunkdata = (char *)&fvar; uint16_t array_read[4] = {1,2,3,4}; float var; chunkdata[0] = array_read[0] + (array_read[1] << 8); chunkdata[1] = array_read[2] + (array_read[3] << 8); var = *(float *)(&chunkdata[0]); }
The MISRA issues are as follows. The line numbering is verified:
2nd update to this thread. In the separate project, I have been able to write code that will break float into chunks and vice versa without any MISRA warnings and errors. I have verified working of the code. Please have a look at it so that I can be sure that this code will always work. Thanks a lot Joseph!!
#include <stdint.h> /******************************************************************************/ /* 32-bit & 64-bit float type from "types.h"*/ /******************************************************************************/ #ifndef C2000_IEEE754_TYPES #define C2000_IEEE754_TYPES typedef float float32_t; typedef long double float64_t; #endif /* C2000_IEEE754_TYPES */ int16_t main(void); float32_t fvar = 0.0f; int16_t main(void) { uint16_t chunkdata[4] = {0};/*8-bit style storage*/ uint16_t intermediate[2] = {0};/*16-bit style storage*/ float32_t var = 14.51234f; float32_t float_new = 0.0f; /*********To break float************************/ /* float -> var */ /* chunks -> chunkdata[4] */ memcpy(intermediate, &var, sizeof(float32_t)); chunkdata[0] = intermediate[0] & 0xFFu; chunkdata[1] = (intermediate[0] >> 8) & 0xFFu; chunkdata[2] = intermediate[1] & 0xFFu; chunkdata[3] = (intermediate[1] >> 8) & 0xFFu; /************************************************/ /**********To join chunks into float************/ memcpy(&float_new, intermediate, sizeof(float32_t)); /************************************************/ return 0; }
Hi Arpan,
Using memcpy is a better solution for allocating space for the new float variable compared to the pointer assignment example that I provided as it violates MISRA C guidelines. I have a concern though that you are still using 16-bit variable 'intermediate' to copy it back as a 'float_new' in the last memcpy statement as the 16-bit variable may not be properly aligned.
Here's a different version that uses just one float variable and copies the contents of that float variable into 32-bit int data which is the ieee754 equivalent using memcpy. A 16-bit array holds the byte data, which can be used to hold the de constructed data from the 32-bit location or vise versa.
float floatdata; Uint32 intdata; Uint16 canbyte[4]; floatdata = 3.1415926; memcpy(&intdata,&floatdata,sizeof(float)); // de-construct 32-bit data into bytes canbyte[0]=intdata&0xff; canbyte[1]=(intdata>>8)&0xff; canbyte[2]=(intdata>>16)&0xff; canbyte[3]=(intdata>>24)&0xff; // group byte chunks into 32-bit number intdata=0; intdata=canbyte[0]+(canbyte[1]<<8)+(((canbyte[2])+(canbyte[3]<<8))*65536); floatdata=0; memcpy(&floatdata,&intdata,sizeof(float));
Regards,
Joseph
Hi Joseph,
According to me, in
memcpy(&float_new, intermediate, sizeof(float32_t));
intermediate is a 16-bit variable. So read to it by memcpy does not require aligned address. What do you think?
Hi Arpan,
I guess so. Going by the definition of memcpy, it copies length of data 'intermediate' from the sizeof function to 'float_new' and as such does not require address alignment.
Regards,
Joseph
Hi Joseph,
So I will stick with the solution I have highlighted as resolved. Thanks a lot for your continuous help over the last 2 days.
Regards,
Arpan