0
\$\begingroup\$

I'm trying to save some floating values to the Data flash of my Nuc220(ARM-M0 32 bit) Microcontroller using ISP procedure.

FMC->ISPCMD = FMC_ISPCMD_PROGRAM;   /* Set ISP Command Code */
FMC->ISPADR = 0x10000;              /* Set Target ROM Address. The address must be word alignment. */
FMC->ISPDAT = 22.5;                 /* Set Data to Program */
FMC->ISPTRG = 0x1;                  /* Trigger to start ISP procedure */
__ISB();                            /* To make sure ISP/CPU be Synchronized */
while(FMC->ISPTRG);                 /* Waiting for ISP Done */


FMC->ISPCMD = FMC_ISPCMD_READ; /* Set ISP Command Code */
FMC->ISPADR = 0x10000;         /* Set Target ROM Address. The address must be word alignment. */
FMC->ISPTRG = 0x1;             /* Trigger to start ISP procedure */
__ISB();                       /* To make sure ISP/CPU be Synchronized */
while(FMC->ISPTRG);            /* Waiting for ISP Done */
dataFloat = (float)(FMC->ISPDAT);

But the value read is 22.0 instead of 22.5 , I also get a warning of, 'implicit conversion to integer' while compilation. How can I do this without error?

\$\endgroup\$
  • 2
    \$\begingroup\$ Are you you sure that ISPDAT is of type float? If you try to assign a floating point value to an integer, it will truncate the value assigned. \$\endgroup\$ – lucas92 Nov 30 '16 at 18:41
  • 2
    \$\begingroup\$ You probably need to get the raw byte data comprising the floating point type and store that as bytes, rather than numeric values, possibly after padding it to a flash word size. Another option in some cases could be to multiply the value by a scaling factor and store that in integer form. There are even cases where converting to a printable character string is sensible, especially in moving between distinct systems or if you want a flash memory dump to be human readable. \$\endgroup\$ – Chris Stratton Nov 30 '16 at 18:48
  • \$\begingroup\$ Oh yeah ISP data is declared in the supporting file as 32bit integer __IO uint32_t ISPDAT; what can I do now? can I change the type to float? \$\endgroup\$ – Arun Joe Nov 30 '16 at 18:49
  • \$\begingroup\$ @lucas92 Hi, I changes it to floating type and it is working now, but is there any way to obtain dual behavior of this register?I mean to shift it to 32 bit integer and floating according to my need? can I try any type casting methods ? \$\endgroup\$ – Arun Joe Nov 30 '16 at 18:54
  • 1
    \$\begingroup\$ Crudely, assuming float and int have the same size and alignment requirements: float f = 2.5f; int *p = (int *) &f ; FMC->ISPDAT = *p; Using a union is probably cleaner though; I'm sure you can find a full example with some searching - you can probably set it up with int, float, and raw bytes fields, etc. \$\endgroup\$ – Chris Stratton Nov 30 '16 at 18:58
6
\$\begingroup\$

Your problem probably arises from an implicit type conversion from a float to an int at this line:

FMC->ISPDAT = 22.5; /* Set Data to Program */

If it were me working on this, I would bundle a float and an int into a union like this:

union {
   uint32_t intVal;
   float floatVal;
} myUnion;

And then simply write the number into the float field:

myUnion.floatVal = 22.5f;

and then read the value as an int like so:

FMC->ISPDAT = myUnion.intVal;

This example assumes that sizeof(float) == sizeof(uint32_t) on your system. Alternatively you can do some compile time gymnastics to make a byte array the same size as your float size like so:

union {
   uint8_t[sizeof(float)] byteArray;
   float floatVal;
} myUnion;

Which works because sizeof is a compile time operator. One additonal note, you'll notice I added an 'f' after the 22.5. This informs the compiler to treat the number literal as a float and not as an int, which evidently is the type it would prefer. This is why your number is being truncated to 22.0, since there is an implicit int conversion taking place, most likely because the ISPDAT member of the FMC struct is an integral type of some kind.

\$\endgroup\$
  • \$\begingroup\$ Hi I tried it using casting without using the 'f' as u mentioned f = 2.5; uint32_t *p = (uint32_t *) &f ; FMC->ISPDAT = *p; and it still works fine , can you tell me the reason? \$\endgroup\$ – Arun Joe Nov 30 '16 at 19:37
  • 2
    \$\begingroup\$ @ArunCheriyan The reason it worked is because there is more than one way to skin this cat. A union simply makes it so that it's members exist at the same memory location, on top of one another. In this instance it is merely syntactic sugar to avoid all the pointers and casting. Since all the members exist in the same memory location, of course pointers and typecasting would work. In my opinion, the union method is more readable, and readable code is important to me. \$\endgroup\$ – Brendan Simpson Nov 30 '16 at 19:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.