This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Passing a float by value or reference

Hi,

We are seeing some strange stuff when trying to pass floating point values to a function. When we pass the parameter by value (meaning as an actual floating point number) the parameters' value changes. When we debug the code we can see that in the disassembly there is a call too __aeabi_f2d. However there should be no reason to call this since all of the values are floats and not doubles. When we pass the floating point number by reference everything works fine.

We are using the nRF52840 with the gcc compiler that comes with the 4.20a version of segger embedded studio.

Meaning this does not work, the value of variable intermediate is not the same value as the value found in input_param :

  float32_t intermediate = *pIncomingSample;
  turn_gyry(intermediate);

void turn_gyry(float32_t input_raw){
  float32_t output_low_pass; 
  float32_t output_moving_average;
  float32_t output_derivative;
  float32_t input_param = input_raw;

  filter_turn_gyry_low_pass(&input_param, &output_low_pass);
  filter_turn_gyry_moving_average(&output_low_pass, &output_moving_average);
  filter_turn_gyry_derivative(&output_moving_average, &output_derivative);

  printf("output low pass %f", output_low_pass );
  printf("output derivative %f", output_derivative);
}

But this works just fine:

  float32_t intermediate = *pIncomingSample;
  turn_gyry(pIncomingSample);

//the function definition of turn_gyry
void turn_gyry(float32_t *input_raw){
  float32_t output_low_pass; 
  float32_t output_moving_average;
  float32_t output_derivative;
  float32_t input_param = input_raw;

  filter_turn_gyry_low_pass(&input_param, &output_low_pass);
  filter_turn_gyry_moving_average(&output_low_pass, &output_moving_average);
  filter_turn_gyry_derivative(&output_moving_average, &output_derivative);

  printf("output low pass %f", output_low_pass );
  printf("output derivative %f", output_derivative);
}

Does anybody have an explanation for this behavior? I believe that the call to __aeabi_f2d implies that for some reason the compiler thinks he needs to convert a float to a double but there is no reason to do this...

Any ideas are welcome

Thanks!

Parents
  • So I checked the code and ran the examples again.

    This case does not work properly and jumps to the aeabi_f2d code (seems to convert float32 to float64) I have no idea why to be honest:

    void dsp_algorithm(float32_t *pIncomingSample, uint32_t counter){
      float32_t intermediate = *pIncomingSample;
      turn_gyry(*pIncomingSample);
    }
    
    turn_gyr_y.c:
    
    void turn_gyry(float32_t input_raw){
      float32_t output_low_pass; 
      float32_t output_moving_average;
      float32_t output_derivative;
      float32_t input_param = input_raw;
    
      filter_turn_gyry_low_pass(&input_param, &output_low_pass);
      filter_turn_gyry_moving_average(&output_low_pass, &output_moving_average);
      filter_turn_gyry_derivative(&output_moving_average, &output_derivative);
    
      previous_output_der = &output_derivative;
    
      printf("output low pass %f", output_low_pass );
      printf("output derivative %f", output_derivative);
    }
    
    turn_gyr_y.h:
    void turn_gyry(float32_t input_raw);
    
    
    

    As you can see in the example above we pass the data as a dereference of a pointer to a float32 to a function that expects a float32. The compiler does not complain about this at all since all the types match. Also when I add a watch point for the variable intermediate or the dereference of pIncomingSample the value is exactly what I expect it to be. I can step through the code and see it get "messed up" by the f2d stuff.

    Now if I change the code to:

    file algo.c:
    
    void dsp_algorithm(float32_t *pIncomingSample, uint32_t counter){
      float32_t intermediate = *pIncomingSample;
      turn_gyry(pIncomingSample);
    
    }
    
    file turn_gyr_y.h:
    
    void turn_gyry(float32_t *input_raw);
    
    file turn_gyr_y.c:
    
    void turn_gyry(float32_t *input_raw){
      float32_t output_low_pass; 
      float32_t output_moving_average;
      float32_t output_derivative;
      float32_t input_param = *input_raw;
    
      filter_turn_gyry_low_pass(&input_param, &output_low_pass);
      filter_turn_gyry_moving_average(&output_low_pass, &output_moving_average);
      filter_turn_gyry_derivative(&output_moving_average, &output_derivative);
    
      previous_output_der = &output_derivative;
    
      printf("output low pass %f", output_low_pass );
      printf("output derivative %f", output_derivative);
    }
    
    

    So in this case we pass the input to the turn_gyry function as a pointer. Now if I check the float32 value in the variable input_param it is passed just fine. I guess my question boils down to: Is it possible that passing float32 values by value is for some reason buggy or faulty while passing them by reference works just fine? The cmsis examples also seem to pass floats by reference but still, in case we do not want to alter the values passed to a function we should be able to pass the value of a variable and not a pointer to the actual variable... I wonder if this is a known issue or if we are missing something.

    Best regards,

    Michiel

  • Hello,

    I can't find any fault in this code either. Things which come to my mind:

    • I'm assuming that this isn't obfuscated C contest where float32_t is misdefined.
    • float32_t intermediate is not used anywhere, delete it?
    • Which optimization setting was used? Is there a difference between no optimization, optimize for size, optimize for speed?
    • Could parameters be made const? e.g. const float32_t * const input_raw.
    • Without seeing the filter function sources, it's not possible to be sure that problem is not in them. 
    • I'm assuming that filter functions return void, even though the return value should not matter.
    • I'm assuming there's no issues with interrupts, memory access violations etc.

    I've been passing floats around as values and by reference and I've never had issue like this, on the other hand I use float rather than float32_t. Then again it should not make any difference on nRF52 chips, as:

    nRF5_SDK_15.3.0_59ac345/components/toolchain/cmsis/include/arm_math.h:283:  typedef float float32_t;

Reply
  • Hello,

    I can't find any fault in this code either. Things which come to my mind:

    • I'm assuming that this isn't obfuscated C contest where float32_t is misdefined.
    • float32_t intermediate is not used anywhere, delete it?
    • Which optimization setting was used? Is there a difference between no optimization, optimize for size, optimize for speed?
    • Could parameters be made const? e.g. const float32_t * const input_raw.
    • Without seeing the filter function sources, it's not possible to be sure that problem is not in them. 
    • I'm assuming that filter functions return void, even though the return value should not matter.
    • I'm assuming there's no issues with interrupts, memory access violations etc.

    I've been passing floats around as values and by reference and I've never had issue like this, on the other hand I use float rather than float32_t. Then again it should not make any difference on nRF52 chips, as:

    nRF5_SDK_15.3.0_59ac345/components/toolchain/cmsis/include/arm_math.h:283:  typedef float float32_t;

Children
No Data
Related