5

I'm trying to read VDDA on an STM32F042 microcontroller. I'm getting unexpected results with VDD at 3.29V. I must be missing something fundamental.

output:

VREFINT=1917; VREFINT_CAL=1524; VDDA=2623 mV
VREFINT=1885; VREFINT_CAL=1524; VDDA=2668 mV
VREFINT=1913; VREFINT_CAL=1524; VDDA=2628 mV
VREFINT=1917; VREFINT_CAL=1524; VDDA=2623 mV
VREFINT=1917; VREFINT_CAL=1524; VDDA=2623 mV

adc_test.c:

#include <stdio.h>
#include "stm32f0xx.h"

#define VREFINT_CAL_ADDR                0x1FFFF7BA  /* datasheet p. 19 */
#define VREFINT_CAL ((uint16_t*) VREFINT_CAL_ADDR)

extern void initialise_monitor_handles(void);

int main(void)
{
    RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;     /* enable ADC peripheral clock */
    RCC->CR2 |= RCC_CR2_HSI14ON;            /* start ADC HSI */
    while (!(RCC->CR2 & RCC_CR2_HSI14RDY)); /* wait for completion */
    /* calibration */
    ADC1->CR |= ADC_CR_ADCAL;               /* start ADc CALibration */
    while (ADC1->CR & ADC_CR_ADCAL);        /* wait for completion */
    ADC1->CR |= ADC_CR_ADEN;                /* ADc ENable */
    while (!(ADC1->ISR & ADC_ISR_ADRDY));   /* wait for completion */
    ADC1->SMPR |= ADC_SMPR1_SMPR_0 |        /* sampling mode: longest */
      ADC_SMPR1_SMPR_1 |
      ADC_SMPR1_SMPR_2;
    /* VDD reference */
    ADC->CCR |= ADC_CCR_VREFEN;             /* VREF Enable */
    ADC1->CHSELR = ADC_CHSELR_CHSEL17;      /* CH17 = VREFINT */

    initialise_monitor_handles();           /* enable semihosting */

    while (1) {
        ADC1->CR |= ADC_CR_ADSTART;             /* start ADC conversion */
        while (!(ADC1->ISR & ADC_ISR_EOC));     /* wait for completion */
        uint32_t vdda = 3300UL * *VREFINT_CAL / ADC1->DR; /* ref. manual p. 252; constant and result in millivolts */
        printf("VREFINT=%lu; VREFINT_CAL=%lu; VDDA=%lu mV\n",
                (unsigned long)ADC1->DR,
                (unsigned long)*VREFINT_CAL,
                (unsigned long)vdda);
    }
}

Screenshot from Datasheet:

enter image description here

Screenshot from Reference Manual

note this refers to .3V, but I believe this to be a typo, as the datasheet above and the longer formula below refer to 3.3V, and .3V is below minimum operating voltage for this part

enter image description here

iter
  • 3,890
  • 6
  • 31
  • 52
  • 2
    I don't see anything obviously wrong with your code, and I can confirm that `.3` instead of `3.3` in the reference manual is indeed a typo (the copy I found online didn't have that error). One wild guess as to the problem - have you perhaps left the Vssa pin floating, instead of connected to ground? (Assuming that you are using a STM32F042 variant that actually has a separate Vssa pin.) Your error in calculating Vdda is suspiciously close to one diode drop, which seems like a plausible outcome if the negative reference voltage is floating. – jasonharper Oct 11 '19 at 01:33
  • 1
    That's an interesting idea, but the pin (pin 32) is connected to GND: https://imgur.com/gMo2GsH Interestingly, the thermal pad isn't connected to anything. – iter Oct 11 '19 at 02:12
  • 5
    That schematic is VERY wrong - it shows the part number for the UFQFNP32 variant of the part, but has the pins labelled according to the LQFP32 variant (which doesn't even have a thermal pad). On the UFQFPN32, pins 16 & 32 are additional Port B I/O pins, and the thermal pad is your *only* ground connection, absolutely required for proper operation. Basically, your chip is only seeing ground via the ESD protection diodes on some I/O pins, and 2.62V *is* an accurate measurement of the power supply as received by the chip. – jasonharper Oct 11 '19 at 02:37
  • 1
    Owwww...... You are exactly right. A previous version of the schematic called for a LQFP32, then it got changed to UFQFNP32, and I guess the hardware guys didn't read the datasheet closely enough. This looks pretty bad... I'm surprised the chip is working at all, and pretty well at that (in the digital domain). Obviously have to fix this in the next spin of the board. As a stop-gap measure, would it help anything to set PB2 and PB8 as inputs instead of high Z, to connect more of the circuitry in the chip to ground, or are the ESD diodes the only path to ground? – iter Oct 11 '19 at 03:29
  • 1
    Don't think inputs vs. hi-Z would make any difference. Setting the pins to output LOW might actually get a better path to ground, although that's living dangerously - even a momentary output HIGH state is likely to fry something. If there's a spot under the chip with no traces, you might be able to mill through from the back side and actually connect to the thermal pad. (Hey, it could be worse - I've seen a similar "wrong footprint" board layout, where the two footprints were basically rotated by 90° - absolutely *nothing* was connected to a usable pin.) – jasonharper Oct 11 '19 at 04:29
  • I hear you. It's a 4-layer board. There is only one trace under the chip in one of the inner layers, but the other inner layer is a solid 3V3 plane. The opposite outer layer is a ground plane. Don't know how easy it would be to avoid shorting the ground and 3V3 planes if we drill through them. – iter Oct 11 '19 at 04:50
  • @jasonharper: as you say, activating pulldowns does nothing, but setting PB2 and PB8 as (low) outputs makes a big difference. VDDA now comes out between 3110 and 3179 mV. OpenOCD reports target voltage as 3.243415. I'm curious if the last .1V discrepancy is a difference between ADCs on programmer and target, or if the ground the chip sees is that much higher than "real" ground. If you want to go ahead and put your insight in an answer to this question, I'll be happy to accept it. – iter Oct 16 '19 at 18:34
  • 1
    I doubt that OpenOCD has any way of measuring the voltage to 7 significant figures... but there's certainly an actual voltage drop, since the entire operating current of the chip is going through the Rds(on) of the low-side FETs on those two pins. (The drop is going to vary based on what the chip is doing, and on the current drawn by other outputs, so your ADC readings aren't going to be very accurate.) As for posting an answer: since the problem turned out to be entirely in hardware, I don't think it belongs here (and Electronics.SE isn't one of the sites that questions can be migrated to). – jasonharper Oct 16 '19 at 19:04
  • This turned out to be a question on electronics, not on software/programming at all. Could you please move it to [electronics.stackexchange](https://electronics.stackexchange.com/) ? – HelpingHand Jun 01 '20 at 07:08
  • 1
    I can see where you're coming from, @HelpingHand. I also note that as a software engineer who discovered a problem with these symptoms, I'd look for an answer here rather than in the hardware section. I want more people to find answers to their questions. – iter Jun 02 '20 at 13:03

2 Answers2

1

I'm currently developing an ADC driver for STM32L4. During implementation I encounter almost the same problem. In my opinion the first formula enter image description here

is not calculating the VDDA, but VREF+. It's the voltage against which the ADC is evaluating the ADC-IN channels. Further the VREFINT_DATA is not measured VREF+ voltage, but an internal reference voltage which is controller dependent. In my case it defined in controller datasheet: enter image description here

Here's a pic how I am using the posted formulas: enter image description here

Some comments: ln 102: calculating VREF+ not VDDA

ln 105-110: calculate all ranks/configured sequence

ln 108: calculate voltage measured by ADCpin_x

ln 109: multiply by gain to get real value

In my opinion by calculating the VREF+ for each conversion sequence, I'll get better results, because so some ripples on VREF+ are compensated.

  • 1
    In my case the answer was improper grounding. Once we connected grounds properly, the formula worked fine. – iter Oct 14 '20 at 01:57
0

Actually it is calculating Vdda, since the Vref calculation is very simple, you have to read the corresponding channel of the ADC with a sample time longer than the one marked in the data sheet (usually 10 us). If Vdda is 2.0 V, a value of 4095 corresponds to 2.0 (or more) V absolute (related GND). In a linear way, the value of Vref will be much higher than if it is read with Vdda = 3.30 V. Therefore, the compensation of the values ​​read with 2.0 V is necessary to know the absolute values ​​of voltage that the ADC is measuring. If they are not compensated, they will be values ​​relative to the voltage level that Vdda has at that moment. In addition, the power supply value is achieved, which will be useful in order not to go beyond the specifications of the microcontroller.

Tristan
  • 1
  • 1