analog inputs unexpected behavior

Hello guys, have been reading the forum for the last weeks and it has been of great help. This is my first post here since I havent found a similar problem in previous post.
So I am using analog inputs to sample current and voltage. Im trying to build some sort of mpp tracker. Im now just working at 0-5 volts levels testing the algorithm but for some reason for the same code in different sketches I am getting different readings for the exactly same setup. I have been scratching my head for more than 2 hours now but cant find the reason for it.
For my tests I use A0 and A1 and connect them to 5V, 0V and 3.3V. With 0V and 5V test everything worked fine but using 3.3V into A0 to simulate a intermediate value and 5V to A1 I get unexpected readings. the voltage measured at the 3.3 V pin is 3.291V so the expected value of analog read is 673 (~3.286V). When I did the first test while writing the code I got the following values

A0 samples 669 669 669 669 669 669 669 669 669 669
read time 216 124 124 124 124 124 124 124 124 124
A1 samples 1023 1023 1023 1023 1023 1023 1023 1023 1023 1023
read time 120 120 120 120 120 120 120 120 120 120
A0 samples 670 670 670 670 670 670 670 670 670 670
read time 120 124 124 124 124 124 124 124 124 124
A1 samples 1023 1023 1023 1023 1023 1023 1023 1023 1023 1023
read time 120 120 120 120 120 120 120 120 120 120

First observation I dont get 673 as expected but 670 which might be close "enough".
I use that same code in other sketch where I added other functionalities but surprisingly the readings are different. Here I get 10 readings and get an average.

A0 avg value 661
A1 avg value 1023
A0 avg value 662
A1 avg value 1023
A0 avg value 662
A1 avg value 1023
A0 avg value 662
A1 avg value 1023
A0 avg value 662
A1 avg value 1023

Now the reading for the same code and setup is different 662 vs 670. That would mean that i will be off by almost 58.58mV from the original value 3.291.

Is this an expected behavior for arduino uno? is it possible that the compiler generates some kind of bug while converting the code? Or am I missing something ? (most probably I am!)

thanks for your help!

After switching between ADC channels, it is usually a good idea to make two readings, and throw the first one away.

Your readings are all referenced to a 5V reference. If your 5V reference isn't exactly 5V then your readings will seem to be off as the Arduino now thinks that 4.95 is 5V or something.

There is an internal 1.1V reference that is a bit more stable and might get you better results.

jremington:
After switching between ADC channels, it is usually a good idea to make two readings, and throw the first one away.

Thanks for the tip, according to the first test it seems all readings are pretty stable even the first one. But i still have to test with the real current sensor and voltage divider to check if that would be necessary.

Delta_G:
Your readings are all referenced to a 5V reference. If your 5V reference isn't exactly 5V then your readings will seem to be off as the Arduino now thinks that 4.95 is 5V or something.

There is an internal 1.1V reference that is a bit more stable and might get you better results.

Hi @Delta_G, that might explain why i get 670 instead of 673 in the first test, but wouldnt the reference be the same when running both sketches? I mean I understand the reading will be a bit off due to the reference not being 5V exactly but shouldnt I get the same readings in both test if the code is the same?
I just want to find a logical explanation to this before I continue building the whole circuits, otherwise when everything is plugged I'll get strange results and would not know where the problem is!

IDK, I can't see any of your code. Maybe one of them does something wrong. It really isn't fair to ask anyone why those two codes do things differently if you're not going to show them the codes in question.

Delta_G:
IDK, I can't see any of your code. Maybe one of them does something wrong. It really isn't fair to ask anyone why those two codes do things differently if you're not going to show them the codes in question.

My bad! here it comes. First test :

void read_IV (){
  int Isense[samples];
  int Vsense[samples];
  int tiempos1[samples];
  int tiempos2[samples];
  for (int i=0; i<samples; i++) {
    int tiempo = micros();
    Isense[i]= analogRead(isense_pin);
    //delayMicroseconds(10);
    
    int tiempo1= micros();
    Vsense[i]=analogRead(vsense_pin);
    //delayMicroseconds(10);      // stabilize ADC S&H
    int tiempo2= micros();
    tiempo= tiempo1 -tiempo;
    tiempo2=tiempo2-tiempo1;
    
    tiempos1[i]=tiempo;
    tiempos2[i]=tiempo2;
    
    }
  Serial.print("A0 samples\t");  
  print_values(Isense,samples);
  Serial.print("read time\t"); 
  print_values(tiempos1,samples);
  Serial.print("A1 samples\t"); 
  print_values(Vsense, samples);
  Serial.print("read time \t"); 
  print_values(tiempos2, samples);
  
    
//  Isense = Isense/samples;
//  Vsense=Vsense/samples;
//  Serial.print (Isense); Serial.print("\t");
//  Serial.print (Vsense); Serial.print("\t");
// 
////  PVvoltage = Vsense*volts_scale;   // Current and voltage scaled by 100
//  PVcurrent = Isense*current_scale;
//  Serial.print (PVvoltage); Serial.print("\t");
//  Serial.print (PVcurrent); Serial.print("\t");

  
  }

second test:

void read_IV (){
  int Isense=0;
  int Vsense=0;
  for (int i=0; i<samples; i++) {
    Isense= Isense + analogRead(isense_pin);
    //delayMicroseconds(10);
    Vsense=Vsense + analogRead(vsense_pin);
    //delayMicroseconds(10);      // stabilize ADC S&H evaluate if required
    }
  Isense= Isense/samples;
  Vsense=Vsense/samples;
  PVvoltage = (long)Vsense*volts_scale;   // Current and voltage scaled by 10000
  PVcurrent = (long)Isense*current_scale;
              Serial.print("A0 avg value \t");// only for debug
              Serial.println (Isense);        // only for debug
              Serial.print("A1 avg value \t"); //  only for debug 
              Serial.println (Vsense);        //  only for debug
              
  }

Only minor difference is the sample averaging!

jremington:
After switching between ADC channels, it is usually a good idea to make two readings, and throw the first one away.

Not here, the 0V, 3.3V and 5V rails are less than 10k impedance, the first reading will be absolutely fine.

The 3.3V reading is expected to be 1024 * V3/V5, where V3 and V5 are the actual voltages on those rails,
in other words the ADC only measures the ratio between its input voltage and the 5V rail (unless you've
reprogrammed it to use the Vref or the internal 1.1V reference)

Measure the voltages carefully and you should see the ADC is +/- one count from expected
(unless you are pulling larges currents from the 5 or 3V rails, in which case IR losses will
disturb your measurements)

MarkT:
Not here, the 0V, 3.3V and 5V rails are less than 10k impedance, the first reading will be absolutely fine.

The 3.3V reading is expected to be 1024 * V3/V5, where V3 and V5 are the actual voltages on those rails,
in other words the ADC only measures the ratio between its input voltage and the 5V rail (unless you've
reprogrammed it to use the Vref or the internal 1.1V reference)

Measure the voltages carefully and you should see the ADC is +/- one count from expected
(unless you are pulling larges currents from the 5 or 3V rails, in which case IR losses will
disturb your measurements)

MarkT, agree with you. The first test was done to check if any delay would be necessary but it seems is not needed. A0 is connected directly to 3.3 V and A1 to 5V through a 47K resistor ;D .

Im using the default reference so 5V. Nothing is connected to the board just the analog signals and a Digital pin just to start running the program. What i dont get is why for the same code (99% same due to the averaging) and exact same connections the readings differ! Whatever the voltage at the 5V and 3V rails it is the same for both test so the readings should be the same right?

I recall this internal reference is +/- 10% so you still need to do some calibration. After that for an individual system it should indeed be very stable, but not exactly precise. For precision you have to use an external precision reference such as the TL431, the B-grade (highest) of which has a <0.5% error on a 2.495V output.

Arduinos are open hardware so it's easy to look up which exact regulators your board has, and check the data sheet for expected errors. The commonly used AMS1117-5.0 regulator produces anywhere between 4.9V and 5.1V according to the data sheet, that's +/- 2% already. The 3.3V regulator will also have a 1-2% error. The ADC is also not perfect and will add its own error, probably also 1-2%.

The error you measure (58.6 mV on 3300 mV) is less than 1.8% difference. That's not too bad. Those three system errors can easily account for that.