cancel
Showing results for 
Search instead for 
Did you mean: 

My MCU's VREFINT_CAL or vrefint channel are not returning proper values. (STM32L073V8Tx)

VWied.1
Associate III

I am currently trying to read my temperate Sensor and Vrefint channel to get the system's temperature and system power voltage. I am measuring 4 other ADCs (11, 12, 13, 15). They are all returning values within an expected range.

0693W00000GYmwKQAT.png 

My expectation is:

  • The temperature should be around 40-80 degC (I am getting 438)
  • Supply voltage to be 3V3 (I am getting 9V)

I have followed the user manual on how to convert these raw ADC values into the expected values. Is there a glaring mistake in my code or is it possible the Calibration values are incorrect?

For temperature, my code looks like this:

/#define TEMP130_CAL_ADDR ((uint16_t*) ((uint32_t) 0x1FF8007E))
/#define TEMP30_CAL_ADDR ((uint16_t*) ((uint32_t) 0x1FF8007A))
/#define VDD_CALIB ((uint16_t) (300))
/#define VDD_APPLI ((uint16_t) (330))
 
int32_t ComputeTemperature(uint32_t measure)
{
  int32_t temperature;
  temperature = ((measure * VDD_APPLI / VDD_CALIB) - (int32_t)*TEMP30_CAL_ADDR );
  temperature = temperature *(int32_t)(130-30);
  temperature = temperature /(int32_t)(*TEMP130_CAL_ADDR -*TEMP30_CAL_ADDR);
  temperature = temperature + 30;
  return(temperature);
}

My VREFINT code looks like this:

#define VREFINT_CAL_ADDR ((uint16_t*)((uint32_t)0x1FF80078U))
 
uint32_t get3v3TimesHundred()
{
    uint32_t vrefintData = adcValues[ADC_3V3]; //value is 614
    uint32_t vrefintCal = (*VREFINT_CAL_ADDR); //value is  1669
    uint32_t vddaCharacteristic = 330; // 3V3 x 100
    uint32_t calculatedVdd = (vddaCharacteristic * vrefintCal) / vrefintData;
 
    return calculatedVdd; //returns ~900 (should be 330?)
}

9 REPLIES 9
TDK
Guru

Probably your sampling time on those channels is insufficient. The datasheet gives a minimum sampling time requirement.

Per the datasheet, VREFINT is nominally 1.224V, so you expect VREFINT_CAL to be:

VREFINT_CAL = 4095 * (VREFINT / VDDA) = 4095 * 1.224 / 3.0 = 1670.76

So the value stored in memory (1669) checks out.

If you feel a post has answered your question, please click "Accept as Solution".
VWied.1
Associate III

My current sampling time is 160.5 Cycles which looks to be the largest value.

To get the ADC values, I am using a DMA channel with a data width of a half word.

Is there anything glaringly wrong with how I am getting the ADC_3V3 value in the code below? It seems to be correct from the information I can find online. From what you are telling me, it must be the ADC read value. If I am doing 160.5 cycles, then I don't know what else I can do to get a better value.

enum
{
  ADC_5V,
  ADC_12V,
  ADC_BATT,
  ADC_FUEL,
  ADC_TEMP,
  ADC_3V3,
  NUM_OF_ADCS
};
 
uint16_t adcValues[NUM_OF_ADCS];
 
uint32_t get3v3TimesHundred()
{
    uint32_t vrefintData = adcValues[ADC_3V3];
    //this is 3.3V times VREFINT_CAL/VREFINT_DATA (stored as 330 meaning 3.3V)
    uint32_t vrefintCal = (*VREFINT_CAL_ADDR);
    uint32_t vddaCharacteristic = 330; // 3V3 x 100
    uint32_t calculatedVdd = (vddaCharacteristic * vrefintCal) / vrefintData;
 
    return calculatedVdd; //This should be very close to 330 (hopefully)
}
 
void RequestAdcUpdate()
{
    HAL_ADC_Start_DMA(adcHandler, (uint32_t*)adcValues, NUM_OF_ADCS);
}
 
main()
{
  RequestAdcUpdate();
  <some delay and other code>
  uint32_t return value = get3v3TimesHundred();
}

TDK
Guru

If VREFINT_CAL = 1669, and you're getting 614, there is something fundamentally wrong with your measurement apart from how you're calculating VDDA. The 3.0V/3.3V mismatch would only explain an error of 10%. I don't see the error in the code you've shown, however there is quite a bit of code that isn't shown.

I would suggest doing a single conversion on the VREFINT channel to narrow down the problem. If that works, then there's a problem in how you're setting up multiple channels. Once VREFINT works, try the temperature calculation in the same manner.

If you feel a post has answered your question, please click "Accept as Solution".
VWied.1
Associate III

So I have tried to only grab the vrefint channel by itself. The raw value I am getting from the ADC measurement is 183 which will calculate to 3009 (expecting 330ish).

I have tried to grab this value by DMA and polling. both of these methods return the same value. Within STM32CubeMX, I have:

0693W00000GYvqaQAD.png 

None of the HAL_ calls only return HAL_OK. There are no errors being caught by the HAL library. The part of the code that I haven't included was:

ADC_HandleTypeDef *adcHandler;
 
void initAdcHardware(ADC_HandleTypeDef *adcHwHandler)
{
    adcHandler = adcHwHandler;
 
    if (HAL_ADCEx_Calibration_Start(adcHandler, ADC_SINGLE_ENDED) != HAL_OK)
    {
        //dealing with error code here
    }
}

The rest of the ADC code is autogenerated via stm32CubeMX.

How exactly are pins 19-22 connected? Also verify for bad solder joints.

Read out and check/post ADC registers content. Check, if VREFINT is enabled in ADC_CCR.VREFEN. Also, read out and check/post content of SYSCFG_CFGR3.

JW

VWied.1
Associate III

19 and 20 are to GND

21 and 22 are to 3v3

From what I can tell, the solder joints look fine. I will get a co-worker to try this and see if they get the same values.

Within stm32l0xx_hal_adc.c:

This if statement is true and ADC->CCR does get set with ADC_CCR_VREFEN:

  /* If VRefInt channel is selected, then enable the internal buffers and path  */
 
  if (((sConfig->Channel & ADC_CHANNEL_MASK) & ADC_CHANNEL_VREFINT) == (ADC_CHANNEL_VREFINT & ADC_CHANNEL_MASK))
  {
     ADC->CCR |= ADC_CCR_VREFEN;  
  }

After the ADC initialization, the values for

ADC->CCR is 0xC00000

SYSCFG->CFGR3 is Hex:0x40000000

I assume ADC->CCR is correct

I am unsure about CFGR3

Do I need to call HAL_ADCEx_EnableVREFINT myself, or should this be handled by CubeMX?

VWied.1
Associate III

I noticed under System Core->SYS->VREFINT_ADC Connection, does this need to be enabled?

0693W00000GYxNBQA1.png

VWied.1
Associate III

I ran it on a second board and it returned with similar out-of-range values.

I just wanted to follow up with you to see if you have any other ideas.