2021-11-24 04:07 PM
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.
My expectation is:
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?)
}
2021-11-24 06:44 PM
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.
2021-11-25 08:28 AM
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();
}
2021-11-25 09:03 AM
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.
2021-11-25 09:46 AM
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:
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.
2021-11-25 11:33 AM
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
2021-11-25 01:03 PM
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?
2021-11-25 01:30 PM
I noticed under System Core->SYS->VREFINT_ADC Connection, does this need to be enabled?
2021-11-25 02:31 PM
I ran it on a second board and it returned with similar out-of-range values.
2021-11-29 04:46 PM
I just wanted to follow up with you to see if you have any other ideas.