cancel
Showing results for 
Search instead for 
Did you mean: 

STM32L432KCU6 ADC returns incorrect values

J.dW
Associate II

Hello everyone,

For a project I'm working on, I'm using the STM32L432KCU6 MCU. After writing some code I've managed to make the STM32L432KCU6 do what I want/need, except that the ADC returns incorrect values from some of the ADC inputs.

In this project I use 6 single-ended ADC inputs, 3 for reading temperature sensors, 1 reading a current feedback and 2 measuring onboard voltages.

The 3 inputs reading the temperature sensors seem to return correct values but the other 3 inputs do not.

Here is an example:

Input# | ADC Value | ADC Volt | Measured Voltage | calculated rounded corresponding ADC Value

IN1 | 3077 | 2.479 | 2.438 | 3026

IN2 | 3085 | 2.485 | 2.447 | 3037

IN3 | 3081 | 2.482 | 2.441 | 3030

IN4 | 2205 | 1.776 | 0.280 | 348

IN5 | 45 | 0.036 | 1.712 | 2125

IN6 | 2761 | 2.224 | 2.113 | 2622

Here you can see that the the first 3 inputs are almost the same as what the ADC returns, but there is something strange happening in IN4 to IN6, especially IN4 and IN5.

The measured voltages given above, are measured using a Fluke 115 as close as possible to the input pins of the MCU. I know that the measured values are correct because of the calculations I did to check them. The current value is equal to the current used by the circuit at that time and is equal to 1A/0.5V. so that is easy to check if it is correct.

I have checked, checked and double checked the hardware, and ofcourse reviewed the software several times, but I can't seem to find the source of this problem.

It isn't a required feature for my project, but I don't like it when something doesn't work as it should.

Thank you for your help in advance, any idea for a possible solution is welcome.

Here are some code snippits (I use CubeMX, HAL)

adc.c

#include "adc.h"
 
#include "gpio.h"
#include "dma.h"
 
/* USER CODE BEGIN 0 */
 
/* USER CODE END 0 */
 
ADC_HandleTypeDef hadc1;
DMA_HandleTypeDef hdma_adc1;
 
/* ADC1 init function */
void MX_ADC1_Init(void)
{
  ADC_ChannelConfTypeDef sConfig;
 
    /**Common config 
    */
  hadc1.Instance = ADC1;
  hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
  hadc1.Init.Resolution = ADC_RESOLUTION_12B;
  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;
  hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  hadc1.Init.LowPowerAutoWait = DISABLE;
  hadc1.Init.ContinuousConvMode = ENABLE;
  hadc1.Init.NbrOfConversion = 6;
  hadc1.Init.DiscontinuousConvMode = DISABLE;
  hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
  hadc1.Init.DMAContinuousRequests = ENABLE;
  hadc1.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
  hadc1.Init.OversamplingMode = DISABLE;
  if (HAL_ADC_Init(&hadc1) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }
 
    /**Configure Regular Channel 
    */
  sConfig.Channel = ADC_CHANNEL_5;
  sConfig.Rank = ADC_REGULAR_RANK_1;
  sConfig.SamplingTime = ADC_SAMPLETIME_6CYCLES_5;
  sConfig.SingleDiff = ADC_SINGLE_ENDED;
  sConfig.OffsetNumber = ADC_OFFSET_NONE;
  sConfig.Offset = 0;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }
 
    /**Configure Regular Channel 
    */
  sConfig.Channel = ADC_CHANNEL_6;
  sConfig.Rank = ADC_REGULAR_RANK_2;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }
 
    /**Configure Regular Channel 
    */
  sConfig.Channel = ADC_CHANNEL_7;
  sConfig.Rank = ADC_REGULAR_RANK_3;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }
 
    /**Configure Regular Channel 
    */
  sConfig.Channel = ADC_CHANNEL_8;
  sConfig.Rank = ADC_REGULAR_RANK_4;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }
 
    /**Configure Regular Channel 
    */
  sConfig.Channel = ADC_CHANNEL_9;
  sConfig.Rank = ADC_REGULAR_RANK_5;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }
 
    /**Configure Regular Channel 
    */
  sConfig.Channel = ADC_CHANNEL_11;
  sConfig.Rank = ADC_REGULAR_RANK_6;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }
 
}
 
void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle)
{
 
  GPIO_InitTypeDef GPIO_InitStruct;
  if(adcHandle->Instance==ADC1)
  {
  /* USER CODE BEGIN ADC1_MspInit 0 */
 
  /* USER CODE END ADC1_MspInit 0 */
    /* ADC1 clock enable */
    __HAL_RCC_ADC_CLK_ENABLE();
  
    /**ADC1 GPIO Configuration    
    PA0     ------> ADC1_IN5
    PA1     ------> ADC1_IN6
    PA2     ------> ADC1_IN7
    PA3     ------> ADC1_IN8
    PA4     ------> ADC1_IN9
    PA6     ------> ADC1_IN11 
    */
    GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3 
                          |GPIO_PIN_4|GPIO_PIN_6;
    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG_ADC_CONTROL;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
 
    /* ADC1 DMA Init */
    /* ADC1 Init */
    hdma_adc1.Instance = DMA1_Channel1;
    hdma_adc1.Init.Request = DMA_REQUEST_0;
    hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;
    hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
    hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
    hdma_adc1.Init.Mode = DMA_NORMAL;
    hdma_adc1.Init.Priority = DMA_PRIORITY_MEDIUM;
    if (HAL_DMA_Init(&hdma_adc1) != HAL_OK)
    {
      _Error_Handler(__FILE__, __LINE__);
    }
 
    __HAL_LINKDMA(adcHandle,DMA_Handle,hdma_adc1);
 
    /* ADC1 interrupt Init */
    HAL_NVIC_SetPriority(ADC1_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(ADC1_IRQn);
  /* USER CODE BEGIN ADC1_MspInit 1 */
 
  /* USER CODE END ADC1_MspInit 1 */
  }
}
 
void HAL_ADC_MspDeInit(ADC_HandleTypeDef* adcHandle)
{
 
  if(adcHandle->Instance==ADC1)
  {
  /* USER CODE BEGIN ADC1_MspDeInit 0 */
 
  /* USER CODE END ADC1_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_ADC_CLK_DISABLE();
  
    /**ADC1 GPIO Configuration    
    PA0     ------> ADC1_IN5
    PA1     ------> ADC1_IN6
    PA2     ------> ADC1_IN7
    PA3     ------> ADC1_IN8
    PA4     ------> ADC1_IN9
    PA6     ------> ADC1_IN11 
    */
    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3 
                          |GPIO_PIN_4|GPIO_PIN_6);
 
    /* ADC1 DMA DeInit */
    HAL_DMA_DeInit(adcHandle->DMA_Handle);
 
    /* ADC1 interrupt Deinit */
    HAL_NVIC_DisableIRQ(ADC1_IRQn);
  /* USER CODE BEGIN ADC1_MspDeInit 1 */
 
  /* USER CODE END ADC1_MspDeInit 1 */
  }
} 

SystemClock config:

void SystemClock_Config(void)
{
 
  RCC_OscInitTypeDef RCC_OscInitStruct;
  RCC_ClkInitTypeDef RCC_ClkInitStruct;
  RCC_PeriphCLKInitTypeDef PeriphClkInit;
 
    /**Initializes the CPU, AHB and APB busses clocks 
    */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI|RCC_OSCILLATORTYPE_MSI;
  RCC_OscInitStruct.LSIState = RCC_LSI_ON;
  RCC_OscInitStruct.MSIState = RCC_MSI_ON;
  RCC_OscInitStruct.MSICalibrationValue = 0;
  RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_6;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_MSI;
  RCC_OscInitStruct.PLL.PLLM = 1;
  RCC_OscInitStruct.PLL.PLLN = 40;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV7;
  RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
  RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }
 
    /**Initializes the CPU, AHB and APB busses clocks 
    */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
 
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }
 
  PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1|RCC_PERIPHCLK_I2C1
                              |RCC_PERIPHCLK_ADC;
  PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK2;
  PeriphClkInit.I2c1ClockSelection = RCC_I2C1CLKSOURCE_PCLK1;
  PeriphClkInit.AdcClockSelection = RCC_ADCCLKSOURCE_SYSCLK;
 
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }
 
    /**Configure the main internal regulator output voltage 
    */
  if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }
 
    /**Configure the Systick interrupt time 
    */
  HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);
 
    /**Configure the Systick 
    */
  HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
 
  /* SysTick_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}

More info needed, just let me know 😉

6 REPLIES 6
AvaTar
Lead

I don't talk Cube/HAL gibberish, and I have not used the L4xx MCU variants yet.

But I suggest to verify you ADC application step-by-step.

First, present fixed voltages at individual channels directly, with sufficiently low impedance. Check that the channel value is in the proper range.

Then include the analog interface circuitry (opamp, level shifter, buffer...), doing the same.

The final step would include the whole chain including sensor, and second a reference measurement for comparison/calibration (like a thermometer for channels 1..3 in your case).

What I find suspicious in your code - the sampling time ( 6.5 cycles) is very short.

I would start at least one order of magnitude higher.

RomainR.
ST Employee

Hi J.dW

Can you share your main function and the code you use to compute and display ADC values ?

I suggest you :

1- Do you perform ADC Calibration ? HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED);

2- Do you really need a sampling rate > 1Msps ? (see below), Can you try to decrease ADC_SAMPLETIME ?  

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.

Rob.Riggs
Senior
J.dW
Associate II

Hello everyone,

First of all thank you all for your replies. I have tested, slowing down the sample rate to the slowest setting "ADC_SAMPLETIME_640CYCLES_5", this didn't solve the problem. continuing with this slower sampling rate I have added the suggested ADC Calibration. Also this didn't solve the problem.

I'm now looking at the given link about optimization etc. to see if that could be of some help.

Note that I'm not a ******** programmer but I have used serveral STM32 MCU's (never a L series) and never had this problem with the ADC's.

I must say that I have noticed that the 3 ADC inputs that return incorrect values, seem to react in a 'floating' way. The returned values bounce around quite a lot. Is it possible that for some reason the ADC channels 8, 9 and 11 initialize with the wrong pin register? so that the MCU returns lets say the values from ADC channel 12, 13 and 14? It's just a brainwave but maybe is possible?

I will get back to you a.s.a.p. when I have tested all your possible solutions.

Dbert.1
Associate

hi

be careful with the output impedance of the analog source connected to adc input pin....must be very low!..if not, or if you put an rc filter in the input pin, for example, you will read wrong values. with 0 volt you will not read zero (actually a bigger value), and with 3.3 volt you will read less than 4095 . The amount of difference depends of the value of this output impedance!!!.

ideally you must put an buffer op amp between signal and input pin (voltage gain=1)

GFell.1
Associate II

Hi,

i'm having a very similar issue, did you mabe find a solution for the mentioned problem?

Thanks