cancel
Showing results for 
Search instead for 
Did you mean: 

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.

JAltu.1
Associate II
 
7 REPLIES 7
RomainR.
ST Employee

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.

JAltu.1
Associate II

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:

0693W00000WHS2CQAX.png 

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

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:

0693W00000WHS2CQAX.png 

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

RomainR.
ST Employee

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.

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

RomainR.
ST Employee

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.

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);