Skip to main content
Visitor II
March 8, 2018
Solved

Erroneous result in arithmetic operations

  • March 8, 2018
  • 3 replies
  • 2369 views
Posted on March 08, 2018 at 16:29

Hi all,

I'm developing an application (PROJECT) for a STM8S208RB (128k flash) t

hat was using around 100kB of flash and I

 have added recently a new library (LIBRARY) that has increased memory usage up yo 120kB

of flash

.

I had an issue because of this event that has been solved. More info in here: 

https://community.st.com/message/188751

  

In the new library I have a function that reads a frequency in Hz (

IE: 208064

) and 

then print it in MHz (IE: 208.064 Hz):

void disp_freq_mhz(void)

{

   uint32_t frequency;

   uint16_t mhz_num, khz_num;

   frequency = frequency_hz;                                                            // frequency_hz 

is a global variable (uint32_t)

   mhz_num = (uint16_t)(frequency/1000);                                      

   khz_num = (uint16_t)(frequency%1000);

   printf (' %03d.%03d MHz', mhz_num, khz_num);

}

The problem is sometimes 

the division and/or modulus operations returns an erroneous value.

I have been debugging this error with STVD in the following way:

  • Known that frequency_hz == 208064, I have added the following code after khz_num assignation:

mhz_num = (uint16_t)(frequency/1000);

khz_num = (uint16_t)(frequency%1000);

if(khz_num != 64 || mhz

_num != 208

)

   return;
  • I have placed a breakpoint in the  return; , so the execution stops when I get a bad division or modulus.
  • This is one reading of the variables involved in the function during one stop (the erroneous values are not always the same):

frequency_hz = 208064

frequency = 208064

mhz_num = 208              

khz_num = 872                          // sometimes it is 640, but most of the time the erroneous value is 872

Result of printf -> ' 208.872 MHz '

Has anybody any idea of why is failing this arithmetic operations?

Thanks all of you in advance,

Guillermo,

#uint16_t #uint32_t #basic-arithmetic
    This topic has been closed for replies.
    Best answer by luca239955_stm1_st
    Posted on March 12, 2018 at 10:27

    Guillermo Corrales wrote:

    I've tried to disable and re-enable interrupts during the division and rest operations and it seems to fix the issue ..

    Best regards,

    Guillermo.

    make sure all your interrupt routines have the @svlreg keyword

    @svlreg @interrupt myIntRoutine() ..

    and see if that fixes the problem.

    3 replies

    Graduate II
    March 8, 2018
    Posted on March 08, 2018 at 16:54

    >>

    Has anybody any idea of why is failing this arithmetic operations?

    I'd hazard that it is doing 16-bit arithmetic.

    Use 1000L instead of 1000, or explicitly cast things to force the math to 32-bit BEFORE converting in to 16-bit.

    Inspect the code output by the compiler to understand the nuances of what has been created.

    Visitor II
    March 8, 2018
    Posted on March 08, 2018 at 17:30

    Hi Clive,

    Thank you so much for your fast response.

    I think it's not an 16-bit arithmetic issue:

    - I tried to cast 1000 to uint32_t before the division / modulus with the same result:

       mhz_num = (uint16_t)(frequency/1000);          ==       

    mhz_num = (uint16_t)(frequency/((uint32_t)1000));  in my case

       khz_num = (uint16_t)(frequency%1000);         ==       

    khz_num

     = (uint16_t)(frequency%((uint32_t)1000))  in my case

    - I have tried to use 1000L instead of 1000, with identical result.

    Do you have another idea?

    Thanks you in advance,

    Guillermo,

    Graduate II
    March 8, 2018
    Posted on March 08, 2018 at 17:46

    Look at the generated code, then you'll understand what the CPU is being told to do.

    You're trying to determine if it is trying to use the quotient/remainder from a single computation, fold constants, etc. Try with optimization on/off, and with the problem code contained to a small and reproducible example.

    If there is a bug with the compiler's code generator or libraries you'd want to submit that to the compiler vendor.

    Visitor II
    March 8, 2018
    Posted on March 08, 2018 at 17:55

    very difficult to imagine that the compiler would get something this simple wrong.

    with that said, if you suspect that the compiler isn't doing its job, there are ways around it.

    for example, I often simply use my own routine to convert numbers to strings:

      //convert tmp to string

      vRAM[7=0; //null terminated string

      vRAM[6]=(tmp % 10) + '0'; tmp /= 10;

      vRAM[5]=(tmp % 10) + '0'; tmp /= 10;

      vRAM[4]=(tmp % 10) + '0'; tmp /= 10;

      vRAM[3]='.';    //vRAM[3]=(tmp % 10) + '0'; tmp /= 10;

      vRAM[2]=(tmp % 10) + '0'; tmp /= 10;

      vRAM[1]=(tmp % 10) + '0'; tmp /= 10;

      vRAM[0]=(tmp % 10) + '0'; tmp /= 10;

    or if you want to go down your path.

      f_khz = frequency / 1000; //khz unit

      f_hz   = frequency - f_khz * 1000; //hz unit

    or other ways of getting around.

    Visitor II
    March 9, 2018
    Posted on March 09, 2018 at 09:08

    Hello,

    I have built and simulated your example and I get the expected values

    0690X00000609XAQAY.png

    If your application fails ''sometimes'' (meaning that doing exactly the same sequence of commands you get sometimes one result, sometimes another), the problem is probably due to some runtime issue, like stack overflow or interrupts corrupting something.

    Regards,

    Luca

    Visitor II
    March 9, 2018
    Posted on March 09, 2018 at 21:22

    I can confirm luca's experience. similarly, I ran OP's code over randomly generated values. and over 10 million runs, all the results are as expected. no error of any kind.

    as if that needs to be confirmed,

    Graduate II
    March 9, 2018
    Posted on March 09, 2018 at 21:44

    The OP's issue is with the COSMIC STM8 compiler

    I'd be suspicious of the code generation, and stack/heap/static corruption.

    In the first case some static inspection of the code would provide some insight.

    If the code looks to be inherently correct it could be separated out and run independently of the surrounding code/application.

    I'd printf('%ld %ld\n',  frequency, frequency_hz);  in the error case to confirm the input conditions, especially for the potential of the global variable being modified.

    Generally chip and compiler bugs would be harder to manifest than this.