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!
1 Answer 1
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 ofelse if (i >= 70 * 0.1)
because it is just the negation of theif (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– dquintero2019年11月05日 14:34:41 +00:00Commented Nov 5, 2019 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– Peter Paul Kiefer2019年11月05日 15:57:42 +00:00Commented Nov 5, 2019 at 15:57
-
I've added a new idea to the answer.Peter Paul Kiefer– Peter Paul Kiefer2019年11月05日 16:35:01 +00:00Commented Nov 5, 2019 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 1chrisl– chrisl2019年11月05日 16:59:03 +00:00Commented Nov 5, 2019 at 16:59
Explore related questions
See similar questions with these tags.