Formula returning wrong answer

For Flowcode users to discuss projects, flowcharts, and any other issues related to Flowcode 2 and 3.

Moderators: Benj, Mods

Post Reply
echase
Posts: 429
Joined: Mon Jun 11, 2007 11:55 am
Has thanked: 49 times
Contact:

Formula returning wrong answer

Post by echase »

I am getting random errors in my formula; could it be to do with this error message?

Serious Warning: Possible sw stack corruption, function '__div_16_16' called by more than one asynchronous thread (main/Task, interrupt, interrupt low)

div_16_1_0004 appears in my CASM file in these places:

A long maths formula within TMR0 interrupt
Various formulae outside interrupt
In Flowcode’s LCD routine

Is it corrupting because the interrupt takes over half way through the __div_16_16 routine and picks up the wrong intermediate results? I can understand how that explanation, if true, would cause the value returned by the interrupt to be wrong but less clear how that would corrupt the formulae outside the interrupt, as the formula inside would complete before returning to outside.

Assuming that division in the formulae is the problem, solutions I can think of are:-

1) I note that when I divide by 2 rather than say 20 __div_16_1_00004 lines are not present. So if I converted my interrupt formula into divisors that were all 2, 4, 8, 16, etc. numbers would it avoid ever needing to use __div_16_16? I am only dividing to shorten the value so that Integer1 * Integer2 does not exceed 32k. Thus /16 or /32 is as good as /20 for this. Can I /16 to avoid __div_16_1_00004 lines or does it have to be /2/2/2/2 instead?

2) Similar to 1) is to in C Code:

Convert integers to binary
Shift byte in lower registers to right by a few places to loose the least significant bits, i.e. effectively dividing by 2, 4, 8, 16, etc. Also shift part of upper one to lower one.
Convert back to decimal.

But no idea how to write that in C.

3) Turn off/on the interrupts before/after every division outside the interrupt, but hard to do in your LCD routine. Also it upsets my timing.

4) Make the formula run quicker so that there is less chance of them clashing in time. I can cope with occasional errors but there are far too many at the moment. If I divide by 2, 4, 8, 16 instead of 3, 5, 20, etc. do the formulae execute much faster? Also I’d have to do the same thing in your LCD routine which is probably impossible.

5) Work in the 32bit realm when doing the interrupt formula, so do not need to divide the 2 integers to shorten them, and then somehow convert the most significant bits back to 16bits without doing a division.

The solution for the interrupt should be the one that executes fastest.

I also call __mul_16s_16 in the interrupt to multiply 2 integers, but not currently outside it. If I were to call it outside I assume I’d have similar error problems, but the above neat solution 1) is not going to help me as the 2 integers to be multiplied are continuously varying and so not 2, 4, 8, 16, etc. Is that correct

User avatar
Steve
Matrix Staff
Posts: 3418
Joined: Tue Jan 03, 2006 3:59 pm
Has thanked: 114 times
Been thanked: 422 times
Contact:

Re: Formula returning wrong answer

Post by Steve »

Ideally, your interrupt routines should be as short and simple as possible and any lengthy or complex code should be done in the main program loop. So I'd suggest that rather than perform the calculations in your interrupt routine, you simply set a flag to say the calculation needs to be done (e.g. set a global "DO_CALC" variable to 1). At a convenient place in your main loop, you should check is this flag is set and then perform the calculation there. Remember to reset your flag after performing the calculation.

echase
Posts: 429
Joined: Mon Jun 11, 2007 11:55 am
Has thanked: 49 times
Contact:

Re: Formula returning wrong answer

Post by echase »

Interesting idea but I fear that it may not be practical as my main loop is quite short, with lots of sub macros in which the processor is spending most of its time. So I may miss the calculation occasionally if I don’t carefully put my flag checks everywhere. That is why I put the formula in the interrupt to be sure it is executed before the next interrupt comes along 500us later, no matter what macro was interrupted. E.g. the LCD macro alone takes >>500us so I’d have to pepper it with flag checks. E.g. write one value to LCD, check flag and calculate if flag set, move cursor, check flag and calculate, write next value, check flag and calculate, etc. Would even that be fast enough?

Do you think my option 1 would work instead and is my problem actually due to _div_16_1_00004?

User avatar
Steve
Matrix Staff
Posts: 3418
Joined: Tue Jan 03, 2006 3:59 pm
Has thanked: 114 times
Been thanked: 422 times
Contact:

Re: Formula returning wrong answer

Post by Steve »

You might find that the complex calculation should only be done at the time you present the data onto the LCD. If this is the case, then performing the calculations only just before the LCD write would make sense.

Your suggestion of dividing by multiples of 2 will certainly make the calculations simpler to perform.

echase
Posts: 429
Joined: Mon Jun 11, 2007 11:55 am
Has thanked: 49 times
Contact:

Re: Formula returning wrong answer

Post by echase »

Steve wrote:You might find that the complex calculation should only be done at the time you present the data onto the LCD. If this is the case, then performing the calculations only just before the LCD write would make sense.
I’d have to save 2000 sets of 2 values from the interrupt (which reads 2 A/Ds) into an integer array (are integer arrays possible?) and then divide /multiply/ sum all these 4000 values in the array before sending to LCD. I guess that might work, as although the A/D reads have to be performed at exactly the right 500us spacing, the calculation can be delayed as LCD is re-written only every 2000 interrupts. Mighty big array?! Maybe have to have several smaller arrays or do sub calculations every 40 samples and save the intermediate answer in a another array?

Option 1 works well. Using 2, 4, 8,16, etc. divisors gets rid of all the div_16_1 lines and speeds up the calculations. No more errors.

OK a long 200us of the 500us interrupt time is taken up with all these A/D reads and formula. But that is down from 300us before I modded the formula and reduced the TACQ time, so it leaves enough time to do all the other tasks, except LCD writes for which I have to turn off the interrupts.

echase
Posts: 429
Joined: Mon Jun 11, 2007 11:55 am
Has thanked: 49 times
Contact:

Re: Formula returning wrong answer

Post by echase »

To avoid my multiplications and divisions inside and outside the interrupt clashing I am having to be a bit inventive. E.g. by doing additions instead of multiplications and then dividing by 2, 4, 8, etc. instead of 3. E.g. Instead of value1 = value *10/3 I will approximate to value1 = value *5/2

Is value1 = value 2 + value 2+ value 2 + value 2 + value 2

The same as value 1 = 5 * value 2 as that avoids a multiplication?

User avatar
JonnyW
Posts: 1230
Joined: Fri Oct 29, 2010 9:13 am
Location: Matrix Multimedia Ltd
Has thanked: 63 times
Been thanked: 290 times
Contact:

Re: Formula returning wrong answer

Post by JonnyW »

Hi Echase. Firstly, yes, no problems with int arrays, though you may be limited by whatever chip you are using (hardware is way over my head though ion a pic8 this will be 127 element array).

Secondly, is what you are doing an averaging program? If so you can save any large calculations by using a moving average filter. If you already know what this is or this isnt what youre doing then I wouldnt bother reading further.

Moving average typically contains three pieces of data:
* An array of the data being processed in a circular buffer
* A 'number of elements' counter
* The total value of all the elements added together

When you read a new piece of data you add it to your buffer and alter the values accordingly. Sorry, this example is written in pseudo-C but Flowcode can do any of this in a flowchart - I will post a sample if youd like. It assumes a 64-element array:

Code: Select all

  total_value = total_value + new_value
  if (current_elements >= max_elements) // Buffer is full so have lost an element of data
  {
    total_value = total_value - data_array[data_index] // Remove the old element from the total
  }
  else
  {
    // Have not reached the limit of elements yet
    current_elements = current_elements + 1
  }
  // Add the new value to the buffer
  data_array[data_index] = new_value
  data_index = (data_index + 1) & 63    // Cycle the 64 element buffer - keeping it a power of 2 saves a division
The average can now be calculated easily at any time using the code:

Code: Select all

  if (current_elements == 0)
    return = 0
  else
    return = total_value / current_elements
This can be put in a macro and read at any time without scanning through a large buffer.

Hope this is what youre after,

Jonny

Spanish_dude
Posts: 594
Joined: Thu Sep 17, 2009 7:52 am
Location: Belgium
Has thanked: 63 times
Been thanked: 102 times
Contact:

Re: Formula returning wrong answer

Post by Spanish_dude »

JonnyW wrote:Hi Echase. Firstly, yes, no problems with int arrays, though you may be limited by whatever chip you are using (hardware is way over my head though ion a pic8 this will be 127 element array).
Wasn't it 128 max elements in an 8 bit PIC microcontroller ?
You maybe meant to say from 0 to 127 elements ?

Anyways, JonnyW's method is the best way to save up memory in your microcontroller.

BR,

Nicolas L. F.

User avatar
JonnyW
Posts: 1230
Joined: Fri Oct 29, 2010 9:13 am
Location: Matrix Multimedia Ltd
Has thanked: 63 times
Been thanked: 290 times
Contact:

Re: Formula returning wrong answer

Post by JonnyW »

Yes, sorry, 128. its probably cos the 7 is next to the 8 on my keyboard.

Post Reply