2019-05-27 08:23 AM
Hello,
I've been using STM32F051C8 on some of my projects and I recently realised that, my ADC is not converting accurately. I connected my Vdda to Vdd, that is 3,3VDC and tried conversation routine below.
Here is the initialisation: Single Channel conversation of ADC2 and I enabled interrupt after conversation.
static void MX_ADC_Init(void)
{
/* USER CODE BEGIN ADC_Init 0 */
/* USER CODE END ADC_Init 0 */
ADC_ChannelConfTypeDef sConfig = {0};
/* USER CODE BEGIN ADC_Init 1 */
/* USER CODE END ADC_Init 1 */
/**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
*/
hadc.Instance = ADC1;
hadc.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
hadc.Init.Resolution = ADC_RESOLUTION_12B;
hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD;
hadc.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
hadc.Init.LowPowerAutoWait = DISABLE;
hadc.Init.LowPowerAutoPowerOff = DISABLE;
hadc.Init.ContinuousConvMode = DISABLE;
hadc.Init.DiscontinuousConvMode = DISABLE;
hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc.Init.DMAContinuousRequests = DISABLE;
hadc.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
if (HAL_ADC_Init(&hadc) != HAL_OK)
{
Error_Handler();
}
/**Configure for the selected ADC regular channel to be converted.
*/
sConfig.Channel = ADC_CHANNEL_2;
sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
sConfig.SamplingTime = ADC_SAMPLETIME_71CYCLES_5;
if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN ADC_Init 2 */
/* USER CODE END ADC_Init 2 */
}
Here is ADC interrupt routine:
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
if (__HAL_ADC_GET_FLAG(hadc, ADC_FLAG_EOC))
{
ADC_BUF[0] = HAL_ADC_GetValue(hadc);
}
}
By the way, I enable ADC interrupt every 2msec:
HAL_ADC_Start_IT(&hadc);
With this routine, I got those conversation values:
Vadc = 0,33V --> ADC Value: 341
Vadc = 0,67V --> ADC Value: 759
Vadc = 1V --> ADC Value: 1176
Vadc = 1,32V --> ADC Value: 1576
Vadc = 1,66V --> ADC Value: 1993
Vadc = 2V --> ADC Value: 2411
I think these values are enough to show, ADC values are not accurate and linear.
Are there anything I missed? What's wrong with the configuration?
Thanks in advance for your help.
2019-05-27 09:02 AM
Did you perform calibration (RM0091, chapter 13.4.1)?
JW
2019-05-27 10:19 AM
What is the input impedence of the analog signal connected to the ADC?
2019-05-27 11:32 PM
I tried calibration but it didn't work. I will try again. Then I'll share the result.
2019-05-27 11:35 PM
Analog signal comes through an op-amp, so there's not significant impedance at the ADC input. I suspect it's because calibration issue. When I tried calibration, it didn't help. Probably I didn't make it properly. I'll try again. Thanks for comment.
2019-05-28 12:23 AM
What board do you talk about ?
> I connected my Vdda to Vdd, that is 3,3VDC and tried conversation routine below.
Not a good idea.
ST's Discovery and Nucleo boards contain schottky diodes in tthe supply paths, to decouple them.
This means your ADC reference voltage will fluctuate with supply source, temperature and supply current.
If you want optimal accuracy, get a proper reference voltage first.
2019-05-28 12:35 AM
I'm using my own board, which power supply is a LDO (LD1117 3V3). I don't see any fluctations when I follow Vdd or ADC Input with oscilloscope.
Is it a must to connect an external reference voltage? I don't think it's needed, likewise most industrial mcu's.
2019-05-28 12:42 AM
It seems an ADC Calibration problem. However, I couldn't manage ADC calibration. When I ran this command:
while(HAL_ADCEx_Calibration_Start(&hadc) != HAL_OK); // calibrate AD convertor
This routine does not end. There's no ADC commands before this command, just ADC Initilisation.
I tried my routine instead of HAL routine, it still didn't work.
hadc.Instance->CR &= ~ADC_CR_ADEN;
hadc.Instance->CR |= ADC_CR_ADCAL;
cnt4break = 100000;
while ((hadc.Instance->CR & ADC_CR_ADCAL) != 0)
{
if (cnt4break != 0) cnt4break--;
else break;
}
This ADC Calibration routine also stuck, and does not end properly. What's wrong or what should I check about ADC Calibration?
2019-05-28 12:53 AM
Is clock for ADC enabled in RCC?
After reset, don't enable ADC until after calibration. But if you did, you can't disable it by clearing the ADEN bit - you have to set ADDIS bit and then wait until ADEN gets cleared by hardware.
JW
2019-05-28 03:31 AM
Thanks waclawek. Your hint helped me to solve calibration problem.
For others, who'd have same problem, here is the solution:
HAL_ADC_Stop(&hadc); //First stop ADC for calibration
while(HAL_ADCEx_Calibration_Start(&hadc) != HAL_OK); // Then run HAL Calibration routine
__HAL_ADC_ENABLE(&hadc); //And then finally enable ADC again
Thanks for all comments and helps.