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.

Saving Floating point to flash

Hello,

I would like to save a floating point number to flash, but I don't want to type cast it to uint32_t because it would floor off the number to an integer.  Is there a good way to do this.  Right now I am just ignoring  the warning it throws when I use a float when it requests a unsigned int:

Here is the call in my code:

float32_t g_nco_I[1];

uint32_t gp_nco_I;

FlashProgram(g_nco_I, gp_nco_I,4);

Here is the warning:

#169-D

argument of type "float32_t *" is incompatible with parameter of type "uint32_t *" 

I appreciate any advice.

Regards,

Curtis

  • Hi,

    It is very simple:

    typedef union {

    float fn;

    uint32_t uln;

    } uni;

    Then alloc space 

    uni flashfn;

    and use it as:

    flashfn.fn = my_flash;

    and save it on flash as flashfn.uln.

    Petrei

  • Hey Petrei,

    Good suggestion, sounds like it should work.  Once I have fixed a fault problem (link below) I am having I will try it out.

    http://e2e.ti.com/support/microcontrollers/tiva_arm/f/908/p/329197/1147231.aspx#1147231

    Regards,

    Curtis

  • Tivaware has a bad API here (it's fairly common in Tivaware to use 32 bit pointers where other pointers would be a better fit to the level of abstraction)

     

    3 fixes possible

    Best - Fix Tivaware

         I doubt TI is going to do this and it will take a fair amount of confidence on your part to do it.

    Worst - Patch around it.  This will work but it's a little ugly and error prone

    (void)FlashProgram((uint32_t *)((void *)&data), address, (uint32_t)(sizeof(data)));

    The void * cast gets rid off the current pointer type and the uint32_t * cast applies the type the function expects.  The void cast on the function call tells readers, compilers and static analyzers that you are deliberatly ignoring the return value. This will get the code past most compilers and static checkers.  Some may require more complex hoop jumping.

    Middling - Build a wrapper around the Tivaware function.  This allows adding appropriate checks and getting rid of unnecessary casts

    typedef enum{
       FE_ERR_ALIGN,
    FE_ERR_SIZE,
    FE_ERR_FAIL,
    FE_ERR_DALIGN,
    FE_SUCCESS
        } FlashError;
    FlashError FlashProgramUser( void *data, uint32_t address, size_t size)
    {
    uint32_t in_addr;

    in_addr = (uint_32_t)data;
         if(     (in_addr %4) != 0) {
    return FE_ERR_DALIGN;
    }
    if( (address%4) != 0) {
               return FE_ERR_ALIGN;


    }
         if( (size%4) != 0) {


               return FE_ERR_SIZE;


     

              }

    if( FlashProgram( data, address,size) != 0) {
    return FE_ERR_FAIL;
    }
    return FE_SUCCESS;

    }

    Now the call becomes

    err = FlashProgramUser( &data, address, sizeof(data));

    Keep in mind none of the code above is tested, it is all freeform entered.  But it should give you some ideas.

    Things that can/should be added to bare bones above. 

    • If you use PC-Lint (recommended) you can add lint sematics to the function that will catch inappropriate usage before you compile.
    • Check size does not exceed functions capability
    • Deal with misaligned source rather than returning error
    • Deal with source that is not a multiple of the flash word size rather than return error

     

    Robert

  • Hey Robert,

    What do you think about the idea of using a union suggested by Petrei?

    - Curtis

  • Using unions is a common way to tackle such problems.

    However, if flash speed and file size is not an issue, using ASCII strings (text) might be a better solution. The resulting files are easier to view and process, and you automatically avoid any endianness trouble.

  • Curtis Mayberry1 said:

    What do you think about the idea of using a union suggested by Petrei?

     
    I don't like it for several reasons
     
    • It's not standards compliant.  In fact as I recall the C standard explicitly warns theat the bit pattern accessed by one member of a union may not match that accessed by another member. As a matter of practice it will almost certainly work on this architecture but it is an easily avoided non-compliance and as such I consider it good practice to avoid.  Basically it is using unions for a job they were not designed to do.  This raises the natural objection that the code is non-portable and non-standard in any case, what does it matter?  It matters for ease of reading and maintenance.  The more standard and portable the code is the less you have to keep in mind when dealing with the code, the more likely standard tools can deal with the code, the less likely you will chip your tooth on compiler extensions and the easier it is to switch vendors (both tools and ICs).
    • It doesn't solve the general problem.  It only solves the case of this specific case where the float and a 32 bit integer happen to share the same size.  It has to be re-written for each separate occurence and checked for size match.  This overhead adds up fairly rapidly especially when you consider that the original writing of the code is a fraction of its useful life.
    • It obscures the code.  Now you have polluted your general code so that all references to your main variable now have an extra indirection.  Also when looking at the data structures you have this odd union that doesn't match the program's basic behavioural structure. 
     
    The middle reason is probably the most immediately, practically important.  Don't discount the importance of clarity and mantenance the other points touch on though.
     
    f.m. has a point about saving data as strings.  I'm not sure it ends up being really applicable to an embdded system without an observable file system though.  It is pretty seldom that you read the raw flash memory to decipher it.  Once you have a file system though the only arguments against using strings are space (often at a premium but less so if you can afford to add something like an SD card) and speed (seldom an issue if you are dealing with items like parameters and faults).  Sometimes the biggest issue with using strings is it brings in all the formatting and precision issues the converting to/from ascii has.
     
    Robert
  • Sometimes the biggest issue with using strings is it brings in all the formatting and precision issues the converting to/from ascii has.

    That might be a valid point against linking with a large library. But it is not really a challenging task to write a binary-to-string conversion function for a specific data type, and with exactly the required accuracy. That avoids most of the *printf overhead of the clib.

    I have used this approach for both serial debugging and SD card access - the latter being an observable file system ...

  • That depends on what you are writing.  For integers absoulutely, it's relatively simple.  Likewise for strings.

    Floating point is another question entirely.  By the time you are done dealing with various NANs, infinities, denormals and values that are exact in decimal but not in binary and vice versa you've got a fair amount of code and testing involved.

    If you have to do ranging and rounding appropriate to the range that introduces another layer of compexity.  I have a colleague who did that for a graphing program.  It's a non-trvial exercise, at least partly because human sensibilities come into play.

    Robert