9 years, 1 month ago.

Different values between read() and read_u16() on F401RE

When reading voltage from AnalogIn on the F401RE, I get different values when using .read() and .read_u16() methods. I updated the firmware and libraries.

the following code:

AnalogIn analog_value(A0);
uint16_t meas = (analog_value.read_u16()); 
float final_1 = (float) 3300 / 65535 * (float) meas;
float final_2 = analog_value.read() * 3300;
printf("Voltage: %dmV or %dmV\n\r", (int) final_1, (int) final_2);

provides the following output:

/media/uploads/drinkinggourd/screen_shot_2015-02-25_at_23.15.13.png

I read some other posts related to this, but things are a little confusing between some of the answers, and the official sample code that uses such calculation as:

define MV(x) ((0xFFF*x)/3300)

Thanks!

2 Answers

9 years, 1 month ago.

Julien, just tried your program on Nucleos with both a F401RE and a F103RB, set the voltage using a potentiometer at A0, GND and 3.3V. The output is almost identical, well there's a small difference of 0...10mV due to rounding errors at the internal calculation as well as separate measurements. From your program I just changed the format statement to:

printf("Voltage: Fin1=%5dmV, Fin2=%5dmV\n\r", (int) final_1, (int) final_2);
  • Voltage: Fin1= 1274mV, Fin2= 1274mV
  • Voltage: Fin1= 1271mV, Fin2= 1281mV
  • Voltage: Fin1= 1275mV, Fin2= 1274mV
  • Voltage: Fin1= 1272mV, Fin2= 1274mV
  • Voltage: Fin1= 1270mV, Fin2= 1271mV
  • Voltage: Fin1= 1273mV, Fin2= 1274mV
  • Voltage: Fin1= 1274mV, Fin2= 1276mV
  • Voltage: Fin1= 1274mV, Fin2= 1274mV

So I could not find the large differences you've seen.

But the define you mentioned is probably an old mistake:

define MV(x) ((0xFFF*x)/3300)

That defines the value of x millivolts, if the analog measurement range equals the 12bit ADC resolution the most STM32 provide. But the internal range of read_u16() is defined as unsigned 16bit as the naming implies. And the range of read() is defined as a float in the range [0.0, 1.0]. You'll find the definitions at the classes of your program within the workspace, e.g. at the mbed compiler.

So your calculation is correct, final_1 calculates from the relation of a 16bit value to it maximum value (65535) multiplied by 3300mV. And final_2 calculates from the precalculated value 0...1 multiplied by again 3300mV.

And if you want to use the define mentioned above: just replace 0xFFF by 0xFFFF when using read_u16(). :-)

Considering you find pretty much the same for both situations, there is a good chance Andy is right: If you have a smaller potentiometer it would work correctly, if he has a large one, possibly on a breadboard with some more capacitance for example, it could cause a dip in the voltage when it is sampled for the second time.

posted by Erik - 10 Mar 2015
9 years, 1 month ago.

Can you try something. Change the code to be

AnalogIn analog_value(A0);
float final_2 = analog_value.read() * 3300;
uint16_t meas = (analog_value.read_u16()); 
float final_1 = (float) 3300 / 65535 * (float) meas;
printf("Voltage: %dmV or %dmV\n\r", (int) final_1, (int) final_2);

Did the values swap over? If so it's not your calculations.

You are initializing the ADC and then reading it quickly twice in a row. Depending on the impedance of the driver and the input it's quite possible that you would get different values for the two reads.