0

I'm currently writing a program in C using Code Composer Studio (CCS) V7.4.0.00015. The program has several self-written libraries that perform Byte, unsigned int and float division.

I have reached that stage in the project where I need to reduce code size in order to ensure there is enough space to fit the boot-loader.

Looking at my .map file reveals several a runtime-support objects that CCS is automatically including. Some of these include the following:

  • div64u.obj --> 846 bytes
  • div64s.obj --> 316 bytes

These objects are from the rts430x_lc_sd_eabi.lib

My question is: Why are these 64bit division objects being included (especially when I don't have any 64 bit floats in my program)? And more importantly, can I disable them (or stop CCS from including them)?

I've spent a few days googling around and trawling different sites but I haven't been able to find much documentation on these objects or how to disable them.

Edit: Turns out I do in fact have one function utilising long long ints (typedef'd as SLLONG)

/**
 * @brief Compensate the raw pressure gained from the BME
 * @details Uses the pressure compensation parameters to 
 *      calculate the true pressure from the raw pressure
 *      
 *      Output value of “96386.2” equals 96386.2 Pa = 963.862 hPa
 *
 *      The contents of this function have been taken from the Adafruit Github page
 *      https://github.com/adafruit/Adafruit_BME280_Library
 * 
 * @param rawPressure The raw pressure
 * @param tempFine The temperature in high resoltuion format, 
 *      gained from the BME_compensateTemp() function
 * 
 * @return the pressure read from the device
 */
float BME_compensatePressure(ULONG rawPressure, SLONG tempFine)
{
    SLLONG var1, var2, p;

    if (rawPressure == 0x800000) // value in case pressure measurement was disabled
        return SNaN;
    rawPressure >>= 4;

    var1 = ((SLLONG)tempFine) - 128000;                                         // SLONG cast to SLLONG 
    var2 = var1 * var1 * (SLLONG)compParamsStruct.dig_P6;                       // SLONG^2 x (SWORD cast to SLLONG) 
    var2 = var2 + ((var1*(SLLONG)compParamsStruct.dig_P5)<<17);                 // SLLONG + (SLLONG * SWORD cast to SLLONG)
    var2 = var2 + (((SLLONG)compParamsStruct.dig_P4)<<35);
    var1 = ((var1 * var1 * (SLLONG)compParamsStruct.dig_P3)>>8) +
           ((var1 * (SLLONG)compParamsStruct.dig_P2)<<12);
    var1 = (((((SLLONG)1)<<47)+var1))*((SLLONG)compParamsStruct.dig_P1)>>33;

    if (var1 == 0) {
        return 0; // avoid exception caused by division by zero
    }
    p = 1048576 - rawPressure;
    p = (((p<<31) - var2)*3125) / var1;
    var1 = (((SLLONG)compParamsStruct.dig_P9) * (p>>13) * (p>>13)) >> 25;
    var2 = (((SLLONG)compParamsStruct.dig_P8) * p) >> 19;

    p = ((p + var1 + var2) >> 8) + (((SLLONG)compParamsStruct.dig_P7)<<4);
    return ((float)p)/256;
}

New question:

  • Can anyone figure out a way to rearrange the function so that it does not require the use of the long long integers (without causing any loss of precision?)
  • OR more specifically, can anyone figure out how I can do that long long division differently i.e the line shown below:
p = (((p<<31) - var2)*3125) / var1;
DaneOH-89
  • 50
  • 6
  • almost all compilers have an option for optimizing for code size such as `-Os` in gcc and `/Os` in MSVC. Check your compiler manual. And I don't think `div64u/s` are for floating-point division. They look like integer division, and they may be used by other utilities that you call – phuclv Oct 15 '19 at 08:42
  • Check your linker documentation for an option to show why it is including a module, and check all your object modules (including those from libraries) for references to these symbols. – Eric Postpischil Oct 15 '19 at 11:37
  • @phuclv I think you're right regarding it being integer division. However, I definitely do not have any 64bit data types in my project. I do have 32bit unsigned and signed ints where math is performed on them. Is there anything I should look for (or avoid) that might be causing this 64bit object to be included? – DaneOH-89 Oct 15 '19 at 23:37
  • @EricPostpischil thanks for the ideas. I'm having a little trouble finding the linker documentation. The linker command file is called lnk_msp430fr2433.cmd. Do you have any ideas for common search terms/keywords I should be using to find the specifics I'm looking for? sorry for the rookiness. – DaneOH-89 Oct 15 '19 at 23:37
  • @EricPostpischil nevermind, I did eventually find the right documentation [here](http://www.ti.com/lit/ug/slau132r/slau132r.pdf) but I can't seem to find anything referencing the div64u.obj or why some objects and not others in the runtime support library are included – DaneOH-89 Oct 15 '19 at 23:57
  • ok. Turns out I do in fact have some long long ints. Please updated question above for more details – DaneOH-89 Oct 16 '19 at 00:41
  • if lower precision is acceptable then just use `(float)((p<<31) - var2)/var1*3125.0f;` since you're already using `float` in your code. But is 316 bytes too big? How much remaining flash do you have? – phuclv Dec 15 '19 at 12:19
  • @phuclv yeah, I might have been overzealous with my attempts to make the code size smaller. I appreciate the input and i'll keep your idea on hand if I find that I need to squeeze that little bit more space out of the code. thanks! – DaneOH-89 Dec 16 '19 at 04:18

1 Answers1

0

Summary of my solution to the original problem of 64bit float operations:

The following lines were first inserted into the compiler flags:

--float_operations_allowed=32

This however produced several errors around the project. The error was the same for each location:

#1558-D 64-bit floating point operations are not allowed

The code that produced these errors was:

float lowerFence = med -1.5 * IQR;
float upperFence = med +1.5 * IQR;

and

return 0.5*coeffs->c0+tempScaled*coeffs->c1;                

The error was fixed by casting literals to floats and moving multiple float operations to single lines

float IQR = STATS_Iqr(sorted, numSamples);
float iqrScaled = 1.5 * IQR;
float lowerFence = med - iqrScaled;
float upperFence = med + iqrScaled;

and

float half = 0.5;
float c0Scaled = half*coeffs->c0;
float c1Scaled = tempScaled*coeffs->c1;
return c0Scaled + c1Scaled;  

After the above errors were resolved, the project was cleaned and rebuilt. Adding this compiler flag had the effect of removing the below objects

DaneOH-89
  • 50
  • 6
  • I believe you'll get much bigger ROM savings by changing `double` literals like `1.5` and `0.5` to `1.5f` and `0.5f`. If you're not aware then floating-point literals without suffix are always double, therefore `float iqrScaled = 1.5 * IQR;` is done by promoting IQR to double, multiply it with the double 1.5 then cast back to float. If you don't need double precision then always use `f` suffix. But for this case you may avoid floating-point completely and use all integers: `int IQR;int iqrScaled = IQR*3/2;` – phuclv Dec 16 '19 at 04:58
  • @phuclv a legendary suggestion! I will implement both methods and see how I go! Thanks so much for the ideas! I really appreciate it – DaneOH-89 Dec 17 '19 at 01:01