0

I am running out of ideas of what may be causing this problem, and I would appreciate some help identifying anything I am overlooking.

Quick Problem Summary

A variable gets set to 32767 quite often and I am unsure why. I tried checking if it was a types problem, if there was somewhere in my code it could overflow, any division by 0, initialising all variables in all sections of the code, and have now tried to cast all relevant variables to int. What else could I try?

This is how this variable gets set in a C++ function:

readValue = readAverage(A0);
targetValue = 2000; // Some constant number set beforehand
myVariable = targetValue - static_cast<int>(round(readValue));

// After some operations that only check if myVariable is within a range

// There are several states in which LOG_myVariable can get set in case there is an error where data wants to get logged
LOG_myVariable = myVariable

All of the variables above are public and get initialised to 0. See in the context section to see how the readAverage function works.

This code block above gets repeated thousands of times in a loop and exits when I send an interrupt. LOG_myVariable only gets set in the method above. Sometimes it gives me normal values that I would expect, but it is returning 32767 very often. Is this some C++ syntax or function I am overlooking?

Some context:

An Arduino Due is using the MATLAB 2019 - Arduino Support Package Add-on. The variables described above are stored in memory and are dynamically overwritten during every logging function. I send them back to MATLAB via the C++ commandHandler as:

byte dataOut[2] = {
                  highByte(LOG_myVariable),
                  lowByte(LOG_myVariable) 
                  };
sendResponseMsg(commandID, dataOut, 2);

In MATLAB, I convert it within a method after requesting the dataOut via sendCommand:

[dataOut] = sendCommand(arduinoObj, arduinoObj.LibraryName, commandID, dataIn);
            % Converts the two High and Low bytes from [dataOut] into a single integer.
            myVariableMATLAB = 256 * dataOut(1) + dataOut(2);

readAverage works like this:

/*
Reads the raw ADC sampled value of a pin an averagePoints amount of times.
All the values get averaged and the function returns `outputAverage`.
Note 
*/
int myClass::readAverage(const uint8_t pin) {
  int i = 1, outputAverage = 0;  // Iteration value, OutputAverage
  double sum = 0, runningAverage = 0;
  // Array Initialization
  int readings[70] = { 0 };

  for (i = 0; i <= 70; i++) {
    if ((runningAverage >= 0) && (runningAverage <= 4096)) {
      // First 10% readings to setup a runningAverage value
      if (i < 70 * 0.1) {
        readings[i] = static_cast<int>(analogRead(pin));
        sum += readings[i];
        runningAverage = static_cast<int>(sum/(i+1));

      } else if (i >= 70 * 0.1) {
        // Normal Operation
        readings[i] = static_cast<int>(analogRead(pin));

        // Filtering Outliers
        // If xReading is within [LOWER_PERCENTAGE, HIGHER_PERCENTAGE] * runningAverage range.
        if ((readings[i] >= LOWER_PERCENTAGE * runningAverage)
        && (readings[i] < HIGHER_PERCENTAGE * runningAverage)) {
          sum += readings[i];
          runningAverage = static_cast<int>(sum/(i+1));
        } else {
          // Enter Error/ Out of Bounds Log Mode, how?
          // Meant to filter out
        }
      }
    } else {
      /* Enter Unknown Error Mode 
      Note it defaults to a single measurement, but no signal is sent to mention this.
      */
      runningAverage = static_cast<int>(analogRead(pin));
    }
  }
  outputAverage = static_cast<int>(round(runningAverage));
  return outputAverage;
}

Any tips on improving the code/logic are always appreciated too!

0

Some findings:

  • Your for loop iterates over 71 results, but your array has only the length 70. You may overwrite variables in the memory behind the array.

  • You can use else instead of else if (i >= 70 * 0.1) because it is just the negation of the if (i < 70 * 0.1). In the else case (i >= 70 * 0.1) is always true.

What is the type of myVariable? If you assign incompatible types (signage or length) an over- or underflow can happen. 32767 = 2^15 - 1 = 0b0011111111111111 (14 bits on) that looks pretty much like an underflow and a conversion of incompatible types.

EDIT:

By a second read of your question I saw another possibility of failure:

You copy the bytes of a two byte signed integer into 2 bytes and send it to matlab.

byte dataOut[2] = {
  highByte( LOG_myVariable ),
  lowByte( LOG_myVariable )  
 };

Let's say you have a negative number in LOG_myVariable. In Memory this is represented with a one in the highest bit (MSBit) and the complementary bit string plus one (two's complement: See Wikipedia).

An Example:

16 bit signed int -1 is represented as 0b1111111111111111 you split it in two bytes 0b11111111 and 0b11111111. The you send it to Matlab.

Now it depends on how Matlab interprets the bytes. Are that unsigned int8 or signed int8? you combine the bytes like so:

 myVariableMATLAB = 256 * dataOut(1) + dataOut(2);

If Matlab interprets the bytes as unsigned you get 256*(-1) + (-1) == -257 but that's not -1. And if it interprets the bytes unsigned it gets 256*255+255 == 65535 which is also not -1. I bet there is a negative number that gives you 32767.

  • Thanks for the help! myVariable is an int. Will write the for loop properly, check if there might be an issue with signage (I had not looked at that before) and again revise types equivalence. Will update if it works. – dquintero Nov 5 at 14:34
  • @dquintero If myVariable is an int then, I doubt that you have problems with negative values. Did you try the correct array size of 71. It's a buffer overflow, and that's a serious error. – Peter Paul Kiefer Nov 5 at 15:57
  • I've added a new idea to the answer. – Peter Paul Kiefer Nov 5 at 16:35
  • Though I haven't read the question fully, 65535 is the max value of a 16 bit unsigned int, which is all bits set to one. If you cast that to a 16 bit signed integer you get -1. 32767 is the max value of a 16 bit signed int, which is all bits except the highest (sign bit) set to 1 – chrisl Nov 5 at 16:59
  • This helped a lot, thanks! – dquintero Nov 6 at 14:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.