This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TMS320F28377S: How to make sure the hex content in memory is the same for floating point value

Part Number: TMS320F28377S

Hi, TI

In my code, 

static float foo=1.08;   // hex value in memory for foo is 3F8A3D71, the actual float value = 1.08000004

foo = 1080.0 / 1000.0;   // hex value in memory for foo becomes 3F8A3D70, the actual float value = 1.07999992

Since we calculate checksum based on hex content, checksum would return a different value even when the actual foo value for our purpose has not changed. Could you please advise whether is there a way that we can guarantee the hex value for the two steps remains the same? Also, please let me know if you need more info.

Many thanks,

Clio

  • Hi,

    I was not able to reproduce the issue as seen below:

    What compiler and object file format are you using? Can you add the 'f' suffix and try? 

    -Shantanu

  • Hi Shanty,

    there were mistakes in my init post, my apologies.

    Please give the following a try:

    static signed long int c = 9200;
    static float a;
    static float b;
    a = (float)c / (10000.0f);
    b = (float)9200 / 10000.0f;

    Many thanks.

    Clio

  • Hi

    to b you assign compile time constant. a is calculated at run time. a should equal b, unless perhaps FPU STF.RND32 is cleared or there's some other reason of disabled FP rounding.

    But I don't understand how do you hit that checksum problem. If you take binary data (including FP variables and constants), checksum that binary data, then perhaps send to PC, of course checksum should match. But if you do some calculations on data between taking checksum and verifying it, then chances are something is calculated differently than expected.

    Edward

  • Hi Edward,

    I checked RND32 in our project, and its value is indeed 0.

    In our project, we have floating-point calculations. How can we get this RND32 set to 1? Can you give us some tips about configuring FPU registers? 

    I've tried to set RND32 to 1, but still not able to get the same hex value. :(

    Regarding the checksum conundrum, we first calculate checksum based on constant, then when the user changes the value (this is when the calculation occurs), we calculate checksum again. that's when we notice the checksum changed without the actual value being changed.

    Again, many thanks for your insights

    Clio

  • Hi Clio,

    Yes, RND32 should be set always, it leads to more accurate results of +-*/, as well affects accuracy of all FP math libs. 

    RND32 is set by default in C2000 compiler library. See in library sources boot28.asm. It has these lines

    .if .TMS320C2800_FPU32
    SETFLG RNDF32=1 ; Enable rounding in FPU32 mode.
    .endif

    Are you using some RTOS? I had problem with FreeRTOS. FreeRTOS sources I used were creating tasks with RND32 cleared...

    Regarding RND32 and division, unfortunately I don't have JTAG dongle by now to test it. Perhaps later, not sure when.

    As I understand, you are using checksum to verify did user alter some settings or not. Then you should pass the same calculation path both when producing initial data and when checking user input. Checksum will match no matter how bad is FP support, no matter is something like RND32 set or not. Perhaps common calculation routine on taking initial checksum and after user input would be the best.

    Edward

  • Hi Edward,

    Yes, we are using boot28.asm, and the part you highlighted is in place.

    From our experiment, it seems that even with RND32 being set to 1, the hex value of a literal float value stored in flash at compile time, e.g. 0.92f, is still different from a floating division performed at run time, e.g. 9200/10000.0f. 

    Therefore, based on our experiment and your comments above, it is our understanding that there is no way to configure the compiler/dsp to produce identical hex values for the above two operations. If you can confirm this statement, we'd focus on our solution some other way. but we appreciate your insight nevertheless. 

    Btw, our initial data is hardcoded float value stored in flash. hence it's a bit hard to have it going thru "the same calculation path".

    Thanks,

    Clio

  • Hi Clio,

    Just curious, which variant you are using a) software FP with compiler strict setting, b) fast math lib, c) TMU and relaxed setting instead of strict?

    I'm testing each new MCU family I use for FP correctness. (at least W.Kahan's Paranoia is my must run for new MCU family / compiler toolchain). No problems with 28377S+-*, they are perfect. But division produces effects like you see.

    Fast math takes reciprocal of divisor, then multiplies by dividend, a * (1/b). According to IEEE754 one FP operation with rounding to nearest mode (RND32) should give result accurate to <=0.5 ULP (unit in least place, or that one bit difference like you see). But since we have two operations in a row instead of one, final result is not accurate to +-0.5 ULP. That's your difference between run time division and division on PC (compiler).

    TMU DIVF32 instruction seems having the same problem like fast math lib. Perhaps internally TMU performs the same two operations, reciprocal + multiply.

    You have two options, a) calculate the same way at runtime, b) take into account possible 1ulp difference. a) shouldn't be problematic for checksum, b) could help only comparting number to number, not good for checksum.

    Edward

  • Hi Edward,

    The settings we are using are: --fp-mode=relaxed, --fp-reassoc=off, f32, tmu0, vcu2 ... having said that, I also experimented with --fp-mode=strict and --fp-reassoc=on, with the same outcome observed, i.e. the hex values being different in two float operations.

    For the moment, we'd accept that this is a limitation in the processor/compiler/library, and focus on working out an alternative with the options you suggested. If you guys ever work out an update for this issue, please let us know. 

    Many thanks for the support, 

    Clio

  • Hi Clio,

    Fastest option with tpu0+relaxes is hardware limited (DIVF32 instruction).

    Slowest option with --fp-mode=strict and software FP division is fixable. Actually I have a fix for this library routine. But would really use this slow option? It doesn't make sense to divide way slower in software while you can use FPU. Unless you do something very accurate using single precission float's, double precision clearly would win in terms of accuracy.  

    Oh, another option for you, since it's user input and shouldn't be fast, why not using double precission (long long double in C2800 compiler). Something like

    b = (long long double)9200 / 10000.0LL;

    Edward

  • Hi Edward,

    I tried using double, no change in the outcome.

    In our project, fp calculation speed is important. Are you saying setting --fp-mode=relaxed results in faster calculation time? I might've diverged from my original question, but which other compiler switches have an impact on fp calculation speed?

    Clio

  • IIRC --fp-mode=relaxed allows compiler to use TMU DIVF32 instruction. With strict you are forced using software FP div emulation. 

    If you have the same problem with double precission div, then looks like long double to float conversion doesn't round. Let me check this next week.

    Edward

  • Hi Clio,

    Indeed  it works

    int c = 9200;

    a = (long double)c / 10000.0L; 

    b = (float)9200 / 10000.0f;. 

    a and b are the same bit to bit

    Edward

    Edit: please don't let compiler full you as me, a should be used, else compiler may optimize out store to a operation. 

  • Hi Edward,

    My compiler is v18.1.1.LTS

    I've tried your suggestion, and it works, highlighted below. But I don't understand why line 647 wouldn't compile 

    I'm glad we have a workaround.

    Thanks for your suggestions,

    Clio

  • v18.1.8LTS is fine with that line, (double)c compiles, though please remember that double is the same like float in TI C2000 compiler, 32 bits. long double is 64 bits.

    Edward

  • Hi Edward,

    Are you saying line 647 below wouldn't compile for v18.1.1.LTS, but would compile with compiler version v18.1.8.LTS?

    I've tried to use double, and long double, but none of what I tried would compile.

    Clio

  • Hi Clio,

    I don't have 18.1.1. With 18.1.8 your former version of line 647 compiled well with proper 64 bit division. New version doesn't look wrong, though perhaps I can't count numerous extra ( ). What error message do you get? If nothing helps. try upgrading your compiler.

    Edward

  • Hi Edward,

    For line 647, I've tried various combinations, but no avail...this is the error msg

    Sure, we will try to upgrade the compiler.

    Thanks,

    Clio

  • Hi,

    Indeed 18.1.8 compiles this just fine

        a = (float)((long double)c) / (10000.00L);

    Could you please post text code instead of pictures next time? It would save my typing.

    Edward