STM32U5 Analog input, can not read values under ~1,6V. With 12-bit resolution, it gets stuck in 2036 even if the voltage goes down.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
2022-11-03 2:06 AM
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
2022-11-04 2:30 AM
Hello JAltu.1 (Community Member)
In order to help you, your request requires more details.
Can you indicate whether you use a custom board or Nucleo/Eval/DK?
The STM32U5 family has two different and independent ADC types (ADC1 and ADC4) which one do you use?
What is your VDDA/VREF schematic for the analog device section?
Finally, can you share your ADC/channel configuration code, input signal characteristics and the method by which you perform the conversion (polling, IT or DMA) ?
Best regards,
Romain,
To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
2022-11-04 3:31 AM
Hi @RomainR.
It is a custom board.
I am using the ADC1.
The microcontroller is STM32U575CIU so it does not have VREF. VDDA is 3V3 and the connection is done with the recommended capcitors:
I am using the polling method and this is the channel configuration:
static void MX_ADC1_Init(void)
{
/* USER CODE BEGIN ADC1_Init 0 */
// get access to PWR
SET_BIT(RCC->AHB3ENR, RCC_AHB3ENR_PWREN);
// switch voltage monitor on
SET_BIT(PWR->SVMCR, PWR_SVMCR_AVM1EN);
// wait until ready
while (READ_BIT(PWR->SVMSR, PWR_SVMSR_VDDA1RDY) == 0);
// switch VDDA isolation off
SET_BIT(PWR->SVMCR, PWR_SVMCR_ASV);
// we do not need access to the PWR domain
CLEAR_BIT(RCC->AHB3ENR, RCC_AHB3ENR_PWREN);
/* USER CODE END ADC1_Init 0 */
ADC_ChannelConfTypeDef sConfig = {0};
/* USER CODE BEGIN ADC1_Init 1 */
/* USER CODE END ADC1_Init 1 */
/** Common config
*/
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
hadc1.Init.Resolution = ADC_RESOLUTION_12B;
hadc1.Init.GainCompensation = 0;
hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
hadc1.Init.LowPowerAutoWait = DISABLE;
hadc1.Init.ContinuousConvMode = DISABLE;
hadc1.Init.NbrOfConversion = 1;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc1.Init.DMAContinuousRequests = DISABLE;
hadc1.Init.TriggerFrequencyMode = ADC_TRIGGER_FREQ_HIGH;
hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED;
hadc1.Init.LeftBitShift = ADC_LEFTBITSHIFT_NONE;
hadc1.Init.ConversionDataManagement = ADC_CONVERSIONDATA_DR;
hadc1.Init.OversamplingMode = DISABLE;
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_5;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_5CYCLE;
sConfig.SingleDiff = ADC_SINGLE_ENDED;
sConfig.OffsetNumber = ADC_OFFSET_NONE;
sConfig.Offset = 0;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN ADC1_Init 2 */
/* USER CODE END ADC1_Init 2 */
}
Than you
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
2022-11-04 3:37 AM
Hi @RomainR. (ST Employee)
It is a custom board.
I am using the ADC1.
The microcontroller is STM32U575CIU so it does not have VREF. VDDA is 3V3 and the connection is done with the recommended capcitors:
I am using the polling method and this is the channel configuration:
static void MX_ADC1_Init(void)
{
/* USER CODE BEGIN ADC1_Init 0 */
// get access to PWR
SET_BIT(RCC->AHB3ENR, RCC_AHB3ENR_PWREN);
// switch voltage monitor on
SET_BIT(PWR->SVMCR, PWR_SVMCR_AVM1EN);
// wait until ready
while (READ_BIT(PWR->SVMSR, PWR_SVMSR_VDDA1RDY) == 0);
// switch VDDA isolation off
SET_BIT(PWR->SVMCR, PWR_SVMCR_ASV);
// we do not need access to the PWR domain
CLEAR_BIT(RCC->AHB3ENR, RCC_AHB3ENR_PWREN);
/* USER CODE END ADC1_Init 0 */
ADC_ChannelConfTypeDef sConfig = {0};
/* USER CODE BEGIN ADC1_Init 1 */
/* USER CODE END ADC1_Init 1 */
/** Common config
*/
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
hadc1.Init.Resolution = ADC_RESOLUTION_12B;
hadc1.Init.GainCompensation = 0;
hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
hadc1.Init.LowPowerAutoWait = DISABLE;
hadc1.Init.ContinuousConvMode = DISABLE;
hadc1.Init.NbrOfConversion = 1;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc1.Init.DMAContinuousRequests = DISABLE;
hadc1.Init.TriggerFrequencyMode = ADC_TRIGGER_FREQ_HIGH;
hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED;
hadc1.Init.LeftBitShift = ADC_LEFTBITSHIFT_NONE;
hadc1.Init.ConversionDataManagement = ADC_CONVERSIONDATA_DR;
hadc1.Init.OversamplingMode = DISABLE;
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_5;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_5CYCLE;
sConfig.SingleDiff = ADC_SINGLE_ENDED;
sConfig.OffsetNumber = ADC_OFFSET_NONE;
sConfig.Offset = 0;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN ADC1_Init 2 */
/* USER CODE END ADC1_Init 2 */
}
Than you
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
2022-11-04 4:17 AM
from your MX_ADC1_Init() function.
I see that you are doing an Enable PWR and VDDA supply. Then you do a Disable PWR Why ?
Can you simply replace following code :
/* USER CODE BEGIN ADC1_Init 0 */
// get access to PWR
SET_BIT(RCC->AHB3ENR, RCC_AHB3ENR_PWREN);
// switch voltage monitor on
SET_BIT(PWR->SVMCR, PWR_SVMCR_AVM1EN);
// wait until ready
while (READ_BIT(PWR->SVMSR, PWR_SVMSR_VDDA1RDY) == 0);
// switch VDDA isolation off
SET_BIT(PWR->SVMCR, PWR_SVMCR_ASV);
// we do not need access to the PWR domain
CLEAR_BIT(RCC->AHB3ENR, RCC_AHB3ENR_PWREN);
/* USER CODE END ADC1_Init 0 */
By:
__HAL_RCC_PWR_CLK_ENABLE();
HAL_PWREx_EnableVddA();
Be sure you have also implemented HAL_ADC_MspInit(ADC_HandleTypeDef* hadc) function to :
- Configure and enable the clock source of ADC1.
- Configure also PA0 as Analog input and that is associated to your ADC1 Channel 5 (you also need to enable the clock for GPIOA)
Finally I recommend to calibrate the ADC1 once before using it:
HAL_ADCEx_Calibration_Start(&hadc1, ADC_CALIB_OFFSET, ADC_SINGLE_ENDED)
Let me know.
BR
Romain,
To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
2022-11-04 5:14 AM
I have changed the code to:
__HAL_RCC_PWR_CLK_ENABLE();
HAL_PWREx_EnableVddA();
I have implemented HAL_ADC_MspInit(ADC_HandleTypeDef* hadc) function and the calibration.
But i still have the same problem. The weird thing is that above 1.6V more or less, it returns correctly the values.
BR
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
2022-11-04 6:09 AM
Is it abnormal that your conversions have an offset equal to VDDA/2 ?
What is your input voltage source, since you are configuring the ADC1 in single-ended mode, is your analog signal is correctly referenced to VSSA/VSS?
What is the ADC1 result conversion if you short PA0 directly to VSSA or VSS ?
Are you able to share your project firmware as an archive ?
BR
Romain,
To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
2022-11-11 3:34 AM
The input voltage source is a 4.2V battery with a voltage divider and the analog signal is correctly referenced to VSSA.
About the project, simplifying the code to this, the same thing happens:
HAL_ADC_MspInit(&hadc1);
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1,100);
Battery = HAL_ADC_GetValue(&hadc1);
