The battery voltage is sampled by a voltage divider and fed into the ADC at PA0. C12 is used to lower the AC impedance of the divider and provides charge to the ADC sampling circuits during a conversion. The 3.3V rail from my LDO is as a voltage reference for the ADC and I probably used some Chinese 5% resistors.
I did some calibration by hooking up an external linear power supply and my 5 digits multimeter. I ran a regression analysis on the data.
The first two columns are the collected data and the rest are the analysis results. Vin can be calculated using
Vin = ADC * 0.001375334 -0.043132682The "Predicted Vin" column are the results using the formula and the "Residuals" are the difference from my input voltage. The error is around - 0.0017V to 0.0014V which isn't too bad.
Using Fast Decimal to Fraction Approximations, I converted the coefficient into a fraction.
I can scale the voltage in mV and use 32-bit integer math for the calculations. The equation becomes
Vin = (ADC * 447000)/325012 - 43 [mV]ADC max = 4095. 4095 * 447000 = 1830465000 which is within 32-bit integer bound.
Formatting the voltage stored in mV to a fixed point is easy. I use the small code size xprintf.c from ChaN's FatFS. It does not support float. either.
Batt = Batt_Read(); xprintf("%01d.%03dV",Batt/1000,Batt%1000);
Voltage reference for ADC
The internal reference source is better than the cheap XC6206P332MR LDO that I am using at 100ppm/C (typ).
The internal reference for the STM32F103 is specified as 100ppm/C max. The ADC reading of the internal reference at operating temperature vs calibration temperature can be used as a scaling factor to correct the results.
For critical applications, the MCP1700T-3302E/TT LDO can be used. It has better tempco comparable to decent a reference source and is footprint compatible.
Temperature measurement
The datasheet shows the following table. The only useful point is the linearity. The rest of the numbers aren't too useful as is without some calibration.I did a rough experiment of measuring the internal temperature sensor and internal reference over temperature. Today is an unusual day as it was very warm in the day time and cool at night. With the help of my freezer, I got 3 temperature points for a linear regression. I do not have enough data point for a proper analysis or did I bother to tape the thermal couple onto the microcontroller to get a more accurate temperature reading. There are quite a bit of improvements that can be made.
Temp column is the measured temperature with a thermal couple.
Ref column is the ADC reading of the internal reference
T Column is the ADC reading of the temperature sensor
T ratio is the temperature reference vs internal reference
The most surprising result is that the "T" column has better correlation than the "T ratio".
The formula for the temperature sensor on my STM32F103 chip is
Temperature = T * -0.151911851511773 + 286.686137163595 [C]I did yet another liner regression using the "Ref" column. For my particular board, the ADC value of the internal reference is a slightly better temperature sensor.