One of our main development boards is the STM32VLDISCOVERY. Its st-link is an in-circuit debugger and programmer, and makes development for prototyping fast and easy. The board has an ‘interesting’ property though: its reference voltage is labeled 3.3V while it is actually… only 3V. Check out the picture for proof!
After reviewing the board schematics we found that a diode ‘D1’ is the cause of this slight voltage drop. The specs of this diode (which is a BAT60JFILM) indicate a forward voltage drop between 0.28V and 0.32V when I=10mA and at a temperature of 25C.
Now, why is this so important for us? Because the ADC peripheral uses this reference voltage…well… as a reference input. And thus, when a 12-bit ADC sample needs to be converted into a more meaningful quantity, we need to know this reference voltage. E.g. a 12-bit value of 1234 corresponds to a 904 mV when Vref equals 3000mV (1234 * 3000/4096) and 994 mV when Vref equals 3300mV. That is a significant difference for control applications! Note also that the resolution of the former is a bit higher (0,73 mV per bit instead of 0,81 mV per bit) while its range is a bit lower.
Usually, this reference voltage is a board-specific define in software. But this only works when the Vref is constant…. which is not the case on the STM32 value line discovery board. The reason is the aforementioned diode for which the forward voltage drop is temperature dependent (see spec).
Bridging the diode is one way to solve this issue (Vref then becomes 3.3V again). But we experimented a bit with the internal voltage reference (V_REFINT) of the ADC peripheral. According to the STM32F100 datasheet (see section 5.3.4 embedded reference voltage) V_REFINT is in the range [1.16V-1.26V] with a typical value of 1.2V. Of course, if this value is also temperature-dependent then we have the same problem as with the diode. This is not very clear from the spec though (please share your experience!).
So, how to get V_REFINT? Via channel 17 of the ADC. If you use the STM libraries then you should configure Channel 17 as a regular channel and then enable via ADC_TempSensorVrefintCmd(ENABLE);. Assuming the typical value of 1.2V, you then can calculate the measured voltage via as follows:
x mV = sample_chx * 1200mV / sample_ch17.
So you use the sample from channel 17 (your reference of 1200mV) in order to calculate the voltage of another channel. This way of working is a bit more board independent because one does not need to know the Vref, only the Vrefint which is spec’d by the MCU.
So how to read voltage on different GPIOs?
We use the STM32 peripheral library. At the moment of writing this comment, it could be found here: http://www.st.com/st-web-ui/static/active/en/st_prod_software_internet/resource/technical/software/firmware/stm32f0_stdperiph_lib.zip
In the documentation and the source code of that library, one will find the requested information. On top of that, we wrote our own abstraction as part of our driver and platform abstraction, since we want to have less coupling between processor (specific libraries) and the rest of the logic in the system.
You can read about that here: http://www.rtos.be/?p=1529
Thanks ! That helped me for a weather station I’m designing for school.
You can also use indirect VRef calibration – connect external reference on ADC input (for ex. TL431 or REF3xxx), periodically measure its voltage, and calculate actual ADC reference from it.
Thanks for your investigation.
Unfortunately different ADC’s multiplexed inputs give different values for the same voltage, therefore I need particular adjustment for each.