Floating Point Parsing Issue on Argon

I have been having an issue with converting a floating point value I read over Modbus that is sent in 4 bytes. I have confirmed via logging that the correct 4 bytes are being read, but I can’t seem to get the conversion right. I have tried various permutations and combinations but of course since floats are a special encoding and not just raw bits, things like fiddling with shifts or reading the single bytes have not been very helpful.

I have previously implemented a working version of this on a different device in Python. This is the very simple code that does the conversion as intended on my ARM7(ARMV7A) 32 Bit Linux System:

res = self.get_input_register(address, 2)

    if res is not None and len(res) > 1:
        floatp1 = res[0]
        floatp2 = res[1]

        float_val = unpack('f', pack('<HH', floatp2, floatp1))[0]

        if self.debug_mode:
            print "FLOAT:" + str(float_val)

This code flips the first 2 bytes with the last 2, so the 2 bytes received 2nd are the MSBs. Then the format string tells the system that this is a Float encoded as 2 variables of type ‘Little Endian unsigned short’ (this system is Big Endian so a conversion is needed).

It is my understanding that the NRF52840 (ARMCortexM4) is Little Endian as well. Therefore, I was hoping something this simple would work:

if (result == modbus.ku8MBSuccess)
{
data[0] = modbus.getResponseBuffer(0);
data[1] = modbus.getResponseBuffer(1);

  int32_t tmpVal = ((uint32_t)(data[1]));
  tmpVal = tmpVal << 16;// shift left 2 bytes
  tmpVal = tmpVal | ((uint32_t)data[0]); // OR in LSB
  float outVal = static_cast<float>(tmpVal);

  Serial.printf("FLOAT: %f", outVal);

}

However, this prints seemingly random/nonsensical garbage data. I have played around with various permutations and combinations of fixes I could think of, but nothing seemed to help. Does anything jump out as an obvious oversight or mistake I’m making?

From this page that was near the top of the Google results, it says that floating point 32-bit big-endian IEEE-754.

As you correctly determined, the ARM processor in all Particle devices is little-endian. It also uses 4-byte (32-bit) for float, and IEEE-754, so the only issue should be the byte order.

I can’t tell for sure if your byte order change is correct. It may or may not be OK.

The definite problem is this line:

float outVal = static_cast<float>(tmpVal);

This won’t do what you want. This basically makes the int32_t into a float that’s still an integer. It’s not doing the bit-wise conversion that you want. You probably want something like this instead:

float outVal = *(float *)&tmpVal;
1 Like

@rickkas7 Thank you very much, the casting thing was it!
To keep it in “C++ Style” I ended up with float floatData = *(reinterpret_cast<float*>(&data)); but your snippt works as well.
I am more experienced/comfortable in C vs C++ so I was misunderstanding the usage of the _cast<> functions in C++, but I did some reading on it and I think I understand now why “reinterpret cast” is the right one.

Thanks again
-Dexter

1 Like