float acting like double

Discussions and support about ChibiOS/RT, the free embedded RTOS.
jcbless
Posts: 43
Joined: Wed Apr 16, 2025 2:29 pm
Has thanked: 7 times
Been thanked: 3 times

float acting like double

Post by jcbless »

I've got this line in main.c:

Code: Select all

static float setVal;


If I set setVal right before using it, then the float seems to get interpreted correctly.

However, if I set setVal in another thread (with or without a mutex protecting it), then the float will get interpreted as a truncated double when processing it to get hexadecimal bytes out.

Do you have any ideas why we might be getting different behaviors when processing setVal from either location?

Thanks,
John
User avatar
Giovanni
Site Admin
Posts: 14891
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: float acting like double

Post by Giovanni »

A float is single precision, 4 bytes in size, manipulating it from another thread makes no difference.

Giovanni
User avatar
alex31
Posts: 445
Joined: Fri May 25, 2012 10:23 am
Has thanked: 57 times
Been thanked: 88 times

Re: float acting like double

Post by alex31 »

This is a strange, not standard behavior.

Do you manipulate the variable directly, or through cast to integral value ?

You can try to declare the variable volatile to force the compiler to access the value through it's memory location.

A.
jcbless
Posts: 43
Joined: Wed Apr 16, 2025 2:29 pm
Has thanked: 7 times
Been thanked: 3 times

Re: float acting like double

Post by jcbless »

I agree that it is strange behavior. I've never seen anything like it before.

The variable is always assigned directly as a float. There is no casting going on.

That's a good point about volatiile. I'll give that a try.
jcbless
Posts: 43
Joined: Wed Apr 16, 2025 2:29 pm
Has thanked: 7 times
Been thanked: 3 times

Re: float acting like double

Post by jcbless »

Now I'm even further confused. If I take the case where things seemed to be working (assigning setVal in the same thread as used) and I add the volatile keyword to the declaration of setVal - now the end result is no longer correct. I'm definitely frustrated by the behavior I'm seeing.

Thanks,
John
User avatar
Giovanni
Site Admin
Posts: 14891
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: float acting like double

Post by Giovanni »

Device? is there a cache involved?

Giovanni
jcbless
Posts: 43
Joined: Wed Apr 16, 2025 2:29 pm
Has thanked: 7 times
Been thanked: 3 times

Re: float acting like double

Post by jcbless »

It is a STM32H753. It does have cache, but I guess it only works with external RAM which I don't think we have.
User avatar
Giovanni
Site Admin
Posts: 14891
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: float acting like double

Post by Giovanni »

It can cache also internal SRAMs so be careful if you access data with DMAs.

Giovanni
jcbless
Posts: 43
Joined: Wed Apr 16, 2025 2:29 pm
Has thanked: 7 times
Been thanked: 3 times

Re: float acting like double

Post by jcbless »

After a recommendation from my manager, I am giving a couple paragraphs of a description to see if that helps describe the situation better:

We have four motors that we’re trying to control via UARTs. The main command we are sending to the motors is a rotational speed command which uses a single precision float. The command is made using functions from the API given by the motor company. Then the command is sent using serial write commands from ChibiOS (sdWrite).

Under certain circumstances when processing the single precision float, the data of the float seems to get converted or processed in some manner as a double precision float. To explain further, if I feed in a variable originally declared as static float setVal, and then send it via a UART, then the data sent on the UART matches the first four bytes of a double precision float for the setVal number. Also, if displaying the same data via a chprintf, the data shown also matches the first four bytes of a double precision float.
jcbless
Posts: 43
Joined: Wed Apr 16, 2025 2:29 pm
Has thanked: 7 times
Been thanked: 3 times

Re: float acting like double

Post by jcbless »

Here's a simplified version of the code in main that relates to the problem:

Code: Select all

static float setVal;

// Definition of Thread1 thread
static THD_FUNCTION(Thread1, arg) {
  while (true) {
    chMtxLock(& mt);
    //setVal = 250.0f;
    vertiqVelocity(setVal, setVal, setVal, setVal);
    chMtxUnlock(& mt);
    chThdSleepMilliseconds(10);
  }
}

int main(void) {
  ...
  while (1) {
    chMtxLock(&mt);
    setVal = 250.0f;
    chMtxUnlock(&mt);
    chThdSleepMilliseconds(1000);
  }
}


Then the code in a file called VertiqInterface:

Code: Select all

...

void vertiqVelocity(float v1, float v2, float v3, float v4){
    vm1.vertiqSetMotorVelocity(v1);
    vm2.vertiqSetMotorVelocity(v2);
    vm3.vertiqSetMotorVelocity(v3);
    vm4.vertiqSetMotorVelocity(v4);
}


And then code in vertiqMotors.cc:

Code: Select all

   ...
    void vertiqMotor::vertiqSetMotorVelocity(float m) {
        if (0 == m) {
            // When m is 0, then set the velocity to MINSPEED
            vertiqSetVelocity(MINSPEED);
        } else {
            // Otherwise, set the velocity proportionately between MINSPEED and
            // MAXSPEED
            //vertiqSetVelocity((float) (std::clamp(m, 0.0f, 1.0f) *
            //                          (float) (MAXSPEED - MINSPEED) +
            //                          (float) MINSPEED));
            vertiqSetVelocity((float) m);
        }
    }
   
    int8_t vertiqMotor::vertiqSetVelocity(float val) {
        //uint32_t * val1 = (uint32_t *)((void *) (& setVal));
        uint32_t val1;
        memcpy(&val1, &val, 4);
        chprintf(chpu, "Float into vSV: %x\r\n", val1);
        prop.ctrl_velocity_.set(com, val);

        //Interface with hardware:

        return vertiqWrite();
    }
   
    int8_t vertiqMotor::vertiqWrite(void) {
        uint8_t packet_buf[64]; // Buffer for packet
        uint8_t length = 0;     // Length of packet

        // Get the packet from the com interface and place it into the packet buffer
        if (com.GetTxBytes(packet_buf, length)) {
            uint32_t * val1 = (uint32_t *)((void *) (packet_buf + length - 6));
            //chprintf(chpu, "Float in write: %x\r\n", * val1);
            sdWrite(chp, (const uint8_t *) packet_buf, length);
            return 0;
        } else {
            return -1;
        }
    }
   


Both the output from chprintf and sdWrite will look like a partial double in this circumstance as written here. However if setVal gets written to the spot where it is commented out at the top of this code, then the output looks like a normal single precision float.
Post Reply