cancel
Showing results for 
Search instead for 
Did you mean: 

Erroneous result in arithmetic operations

Guillermo Corrales
Associate II
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
1 ACCEPTED SOLUTION

Accepted Solutions
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.

View solution in original post

13 REPLIES 13
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.

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
henry.dick
Senior II
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.

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,

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.

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
luca239955_stm1_st
Senior II
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

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,

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.

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
Posted on March 09, 2018 at 22:03

still, it is difficult to imagine that cosmic would get something this simple wrong - that compiler is widely used and if they got this wrong, it would be widely reported.

on the flip side, compiler bugs are very easy to find, especially for newbies,

Posted on March 09, 2018 at 23:07

well, the same code running on a stm8s003 / cosmic has shown no sign of failure after 2+ hours.