Looking for clever way to store 32bit float constants in array to initialize byte-wide eeprom

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Looking for clever way to store 32bit float constants in array to initialize byte-wide eeprom

2,171 Views
PG1
Contributor I

I am doing alot of software testing and have written code to force data into a byte wide eeprom. Normally the EEPROM would be loaded by production support equipment from a hex file.

 

 The eeprom contains many types (byte, int, long, float, double) . I need to put some 32 bit floating point constants into the array, but how could I use a macro to split up the 4 bytes of the floating point to align to the natural size of the byte wide eeprom.

 

Hopefully this will clarify:

 

 

#define REV 0

#define PRODUCT_TYPE 0

#define PI 3.1415     //pi is a ieee754 32bit type

 

 

//This is the array which will be loaded into NVRAM for software testing purposes

 

const Byte gNVRAMInitialValues[ SIZE_OF_NVRAM ] =
                                         { REV, PRODUCT_TYPE, MSB_OF_PI, BYTE2_OF_PI, BYTE_3_OF_PI, LSB_OF_PI}; 

 

 

In other words, what is the macro definition for the four bytes MSB_OF_PI, BYTE2_OF_PI, BYTE_3_OF_PI, LSB_OF_PI which represent PI as an ieee754 32 bit

Labels (1)
Tags (1)
0 Kudos
Reply
8 Replies

1,586 Views
kef
Specialist I

Why don't you use struct?

0 Kudos
Reply

1,586 Views
PG1
Contributor I

2000 bytes of  heterogenous data types makes for a complicated struct and union, and I probably should not assume the struct is contiguous in flash if I want to pretend its an array starting at the beginning address of the struct.

 

Ive seen people do it but your not supposed to because of banking (or padding and alignment on other architectures).

0 Kudos
Reply

1,586 Views
kef
Specialist I

PG1,

 

Indeed it is safe to assume struct is contiguous in flash, the same like array of chars. But if you are going to send it as is as a binary to PC or to some other device, then of course you should consider padding bytes inserted to align misaligned struct members. Butr CW 16-bit compilers don't insert any padding bytes (except CW for XGATE and optional enable of struct padding on S12X, which is off by default).

 

I wonder how are you going to use this heterogenous struct? Are you 1) just sending it as binary to PC or some networked device? Or indeed 2) you are accessing these floats and doubles somehow? For 1st, with the help of preprocessor you could both declare and define your struct in some header file like comes below. I'm using it, and it greatly simplifies the task. One inconvenience is that you need to enumerate your records somehow, becouse you can't have two or more struct members with the same name. So if it is what you need, you do header like below and include it twice in your C file, one time with define_data not defined and 2nd time with define_data defined... . Let me know if this is what you need and and if you need the help

 

#ifdef define_data

  .. define macro for initializer of float record   floatrec(..)

  .. define macro for initializer of fdouble record   doublerec(..)

  ... struct define header like typedef struct {

#else // declare data

  .. define macro for declaration of float_record floatrec(...)

  .. define macro for declaration of fdouble record   doublerec(..)

  ... struct declare header  like const mydataT mydata={

#endif

 

   //////////////////   define you data here /////

   floatrec(    uniqueid1, 1.34)

   doublerec(uniqueid2, 2.45)

   floatrec2(  uniqueid3, 1.34, 3.44)

   ...

   /////////////////////////////////////////////////////////

 

#ifdef define_data

  ... struct define header

#else // declare data

  ... struct declare header

#endif

 

  .. undefine macro floatrec(...)

  .. undefine macro doublerec(..)

 

0 Kudos
Reply

1,586 Views
PG1
Contributor I

Thanks for all the suggestions. It would appear that there is no macro to split up the 4 bytes of a 32bit float constant, unlike say:

 

#define SOME_INT_VALUE 2043

#define LOW_BYTE_OF_INT(x) x&0xFF  

#define HIGH_BYTE_OF_INT(x) (x>>8)&0xFF  
unsigned const char gNVRAMInitialValues[ SIZE_OF_NVRAM ] =
                                         {
                                          LOW_BYTE_OF_INT(SOME_INT_VALUE) ,   

                                          HIGH_BYTE_OF_INT(SOME_INT_VALUE)}                  

 

kef- the purpose is to create a blob of data which is forced into an nvram at startup so that fault detection code in the applcation can be tested. This might be putting in an out of range float. Or I might damage one byte of a float in the blob, for example, to simulate an incomplete write. No transmission of data outside the product is involved.

 

I chose to make the blob into an array, not a struct/struct-union.

 

I had avoided making the blob into a big struct/union because its tedious for 2000 bytes of data.  Also, the app does not need a big struct/union blob. For example, to get any kind of data out of the NVRAM and into a variable I use:

 

ReadNVRAMArbitraryNumOfBytes( U16t nvram_address, U8t length, void * place_to_store_data_read_from_nvram);

 

The caller specifies the appropriate length and is responsible for ensuring that the  place to store data is the right type. Also the caller must ensure the starting nvram_address is correct. MACROs for the first two arguments help alot.

0 Kudos
Reply

1,586 Views
kef
Specialist I

It is easy to split float or double into bytes *at runtime*, but all existing methods require float to be allocated in memory. Then you either use union to extract bytes, or typecast address of float to char* and then access individual bytes of float. This of course doesn't work for const initializer, which needs to be done at compile time. Also both methods are not portable, since they debend on endianess of target.

What works for integer variables, >>8 and typecast to char also doesn't work for float for two reasons 1) there's no >> operator that would work with float, also 2) typecasting float to int/char will attemt to convert from floating point to integer, which is not what you want.

 

You may put into the struct not only legal floats, but any types, including fixed arrays of chars and even variable length string literals.

0 Kudos
Reply

1,586 Views
PG1
Contributor I

Thanks for your help!

0 Kudos
Reply

1,586 Views
rocco
Senior Contributor II

Hi PG1,

 

Actually, when I read Kef saying "struct", I found myself saying "yeah, struct". But what I really meant (and what I thought Kef meant) was "yeah, union". I was thinking that a union would be the best way to access the four bytes of the 32-bit floating point value.

 

But I don't use CodeWarrior, so I'm not the best one to ask . . .

0 Kudos
Reply

1,586 Views
bigmac
Specialist III

Hello,

 

I had assumed that the OP was referring to internal EEPROM within the device, and this was to be programmed (with  the required initial values) when the code is programmed to flash.  On this basis, I might have assumed the use of a struct to handle the different data types.  However, I cannot see the need for handling the individual bytes since each variable can simply be read as an element of the structure.

 

struct str1 {  byte b;  word w;  dword d;  float f;};const struct str1 nvdat1 = {1, 1000, 100000, 3.14159};...float val;val = nvdat1.f;

 

With as many as 2000 bytes of NV data, I would suppose that this would be broken into a number of different structures, for handling the data in managable chunks.

 

I can imagine a different scenario, where it would be necessary to handle complex data as individual bytes.  This is where an external serial EEPROM is used, and it is necessary to utilize a function in order to write or to read individual byte values.  For this case, a union might be used for each basic data type.  Of course, big endian data format is assumed in the example shown.

 

typedef union {  word w;  byte b[2];} WORDSTR;typedef union {  dword dw;  byte b[4];} DWORDSTR;typedef union {  float f;  byte b[4];} FLOATSTR;...  word EE_addr;        // Serial EEPROM address  ...    // Program default data from flash  EE_addr = EE_wrfloat( EE_addr, nvdat1.f);  ...word EE_wrfloat( word addr, float fval){  byte i;  FLOATSTR ftemp;  ftemp.f = fval;  for (i == 0; i < 4; i++)     EE_prog( addr++, ftemp.b[i]);  return addr;} 

 

 Regards,

Mac

 

0 Kudos
Reply