4

I want to store some float data in the FRAM register of my TI MSP430 microcontroller and have some prolems.

I don't know how I can do this.

With normal integer variables it is no problem.

Normal integer variables:

void main()
{
    uint32_t value = 25;
    uint32_t framPtr = 0xD000;

    FRAMC_write_uint32_t(value, (uint32_t*)framPtr);
}

void FRAMC_write_uint32_t(uint32_t value,
                          uint32_t *framPtr)
{
    *framPtr = value;
}

But with float values it doesn't work. I tried to change the value inside the function to float, but no result.

This is my float data:

    float value = 1.25;
    uint32_t framPtr = 0xD000;

With this function it doesn't work:

void FRAM_write_float(float value,
                      uint32_t *framPtr)
{
    *framPtr++ = (float)value;
}

It saved the data 1.40129846e-45 (DEN) (HEX: 0x00000001) in my memory bank.

I hope somebody can help me with my problem. Thanks!

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
Pantastisch
  • 135
  • 1
  • 1
  • 11
  • 1
    Casting a float to an integer doesn't reinterpret the bits, if that is what you are after. It does value conversion. – StoryTeller - Unslander Monica Jan 15 '17 at 12:23
  • I'm guessing. Because you didn't show how you attempt to actually convert the float. Why you are showing code that *works* instead of code that doesn't is beyond me. – StoryTeller - Unslander Monica Jan 15 '17 at 12:25
  • What is the difference? I don't understand the problem... When I look into the memory bank, I see the saved value is 1.40129846e-45 (DEN) (HEX: 0x00000001) – Pantastisch Jan 15 '17 at 12:28
  • The difference is that `0x00000001` may be an integer representation of `1`, but for floats `0x3F800000` would be `1.0`. Converting values as opposed to reinterpreting bits will have drastically different results. – StoryTeller - Unslander Monica Jan 15 '17 at 12:34
  • Ah, now I understand the problem. But I didn't know how I solve the problem. How can I say my program to shift my float data without converting it to an integer? – Pantastisch Jan 15 '17 at 12:37
  • Are you programming in C or C++? The best answer depends on it (and one is not a subset of the other). – StoryTeller - Unslander Monica Jan 15 '17 at 12:38
  • I am programming my microcontroller only in C. I thought there are many comparrison. Should I delete the C++ tag? – Pantastisch Jan 15 '17 at 12:41
  • They are quite different. Type punning, which is what I suggested, is not officially allowed in C++, but is allowed in C99 and beyond (with some warnings to the programmer). – StoryTeller - Unslander Monica Jan 15 '17 at 12:45
  • 1
    Your code invokes undefined behaviour. Any reason you don't serialise the data to an `uint8_t` array? And on MSP430 you should not use floating point anyway. It has no FPU and calculations easily take >100 times longer than with integers. Most algorithms for such MCUs can be rewritten quite easily with integers. – too honest for this site Jan 15 '17 at 13:59

1 Answers1

12

The simplest approach to reinterpret the bits would be to use memcpy, if you know that sizeof(float) == sizeof(uint32_t) 1

float f = /* some_val */;
uint32_t fbits = 0;
memcpy(&fbits, &f, sizeof fbits);

Should be safe enough, since unsigned integers don't usually have trap values.

If your compiler supports C99 and onward. You can also do type punning via a union.

union {
  float    from;
  uint32_t to;
} pun = { .from = /*some val*/ };

// use pun.to

The above doesn't actually copy anything, so may be marginally faster in a tight loop. (And as Olaf points out, this is the standard compliant way for modern C).


1: If your compiler supports it, you should probably _Static_assert on it.

Community
  • 1
  • 1
StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
  • @StorryTeller It works! I used the above one to solve the problem. **Thank you!!** – Pantastisch Jan 15 '17 at 12:58
  • 1
    @Olaf - Isn't memcpy/memove the only way to change the effective type of an object in pre C99? I'm asking, because that's what I've usually seen done. – StoryTeller - Unslander Monica Jan 15 '17 at 14:08
  • 1
    @StoryTeller: See the C info-page, we are talking about **standard** C, which is C11. And that is clear about that. See 6.5p6 and the explicit remark about type-punning via `union`. Things were different if OP used a `uint8_t` (which must be the same as `unsigned char`). Anyway, I'd take a different approach and not use floating point at all on the MSP430 (the problem applies to other types like `int64_t` as well, of course). – too honest for this site Jan 15 '17 at 14:11
  • @Olaf - Okay so [§6.5 ¶6](http://port70.net/~nsz/c/c11/n1570.html#6.5p6) prevents me from changing the effective type of `f` here. And I see that according to [§6.2.6.1 ¶4-5](http://port70.net/~nsz/c/c11/n1570.html#6.2.6.1p4) I'm advising the OP something risking UB. But I must say that I fail to see how type punning of a value may technically work, while memcpy will fail horribly. Any way, thank you for pointing those things out! – StoryTeller - Unslander Monica Jan 15 '17 at 14:24
  • 1
    @StoryTeller: You'd be surprised what a modern, highly optimising compiler exploits. That's one reason gcc has (had) a bad rep with embedded programmers (Personally, I like it!). They just assumed some behaviour like assembly did. Note that most of them were not CS experts, but hardware-engineers who learn programming, but not necessarily how a compiler works and the nasty language details. Which is also the reason quite some refused HLLs like C much longer than reasonable. And those are also the rason for commercial compilers being much more conservative using optimistations. – too honest for this site Jan 15 '17 at 14:30