cancel
Showing results for 
Search instead for 
Did you mean: 

ADC "shorting" analog input to GND

madsttygesen
Associate

We're using the following circuit to measure a battery voltage @ 20 kHz for use in motor control.

DC_bus_measurement.png

We are having some issues though, where the ADC suddenly starts measuring 0 V (0 in the data register) and gets locked in this state. In this state, we also measured 0 V at the MCU pin on the board, and a resistance < 20 Ohm between the pin and GND, both using a multimeter. The issue is not fixed by a reset (pulse on the NRST pin), only removing the battery and power cycling the MCU.

How and why can/does this happen?

We initially thought it was overvoltage and tried connecting a PSU directly to an ADC pin on the STM32G474RE NUCLEO board. We only started seeing abnormalities at 6 V and destroyed the ADC at around 9 V, so this does not seem to be the reason.

The ADC is clocked 170/4 = 42.5 MHz and configured as follows (from IOC file):

ADC1.CommonPathInternal=null|null|null|null
ADC1.DMAContinuousRequests=DISABLE
ADC1.EOCSelection=ADC_EOC_SEQ_CONV
ADC1.EnableAnalogWatchDog1=false
ADC1.EnableInjectedConversion=ENABLE
ADC1.EnableRegularConversion=DISABLE
ADC1.ExternalTrigInjecConv=ADC_EXTERNALTRIGINJEC_T1_TRGO
ADC1.IPParameters=EOCSelection,EnableRegularConversion,EnableInjectedConversion,EnableAnalogWatchDog1,DMAContinuousRequests,master,InjectedRank-10\#ChannelInjectedConversion,InjectedChannel-10\#ChannelInjectedConversion,Rank1_Channel,InjectedSamplingTime-10\#ChannelInjectedConversion,InjectedOffsetNumber-10\#ChannelInjectedConversion,Rank2_Channel,InjNumberOfConversion,ExternalTrigInjecConv,Overrun,InjectedRank-13\#ChannelInjectedConversion,InjectedChannel-13\#ChannelInjectedConversion,InjectedSamplingTime-13\#ChannelInjectedConversion,InjectedOffsetNumber-13\#ChannelInjectedConversion,CommonPathInternal
ADC1.InjNumberOfConversion=2
ADC1.InjectedChannel-10\#ChannelInjectedConversion=ADC_CHANNEL_3
ADC1.InjectedChannel-13\#ChannelInjectedConversion=ADC_CHANNEL_2
ADC1.InjectedOffsetNumber-10\#ChannelInjectedConversion=ADC_OFFSET_NONE
ADC1.InjectedOffsetNumber-13\#ChannelInjectedConversion=ADC_OFFSET_NONE
ADC1.InjectedRank-10\#ChannelInjectedConversion=1
ADC1.InjectedRank-13\#ChannelInjectedConversion=2
ADC1.InjectedSamplingTime-10\#ChannelInjectedConversion=ADC_SAMPLETIME_2CYCLES_5
ADC1.InjectedSamplingTime-13\#ChannelInjectedConversion=ADC_SAMPLETIME_2CYCLES_5
ADC1.Overrun=ADC_OVR_DATA_OVERWRITTEN
ADC1.Rank1_Channel=ADC_CHANNEL_3
ADC1.Rank2_Channel=ADC_CHANNEL_2
ADC1.master=1

PA2.Mode=IN3-Single-Ended
PA2.Signal=ADC1_IN3

And the following code (generated mostly by CubeMX) is used for initialisation

/* ADC1 init function */
void MX_ADC1_Init(void)
{

  /* USER CODE BEGIN ADC1_Init 0 */

  /* USER CODE END ADC1_Init 0 */

  ADC_MultiModeTypeDef multimode = {0};
  ADC_InjectionConfTypeDef sConfigInjected = {0};

  /* USER CODE BEGIN ADC1_Init 1 */

  /* USER CODE END ADC1_Init 1 */

  /** 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.GainCompensation = 0;
  hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;
  hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV;
  hadc1.Init.LowPowerAutoWait = DISABLE;
  hadc1.Init.ContinuousConvMode = DISABLE;
  hadc1.Init.NbrOfConversion = 1;
  hadc1.Init.DiscontinuousConvMode = DISABLE;
  hadc1.Init.DMAContinuousRequests = DISABLE;
  hadc1.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
  hadc1.Init.OversamplingMode = DISABLE;
  if (HAL_ADC_Init(&hadc1) != HAL_OK)
  {
    Error_Handler();
  }

  /** Configure the ADC multi-mode
  */
  multimode.Mode = ADC_MODE_INDEPENDENT;
  if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)
  {
    Error_Handler();
  }

  /** Configure Injected Channel
  */
  sConfigInjected.InjectedChannel = ADC_CHANNEL_3;
  sConfigInjected.InjectedRank = ADC_INJECTED_RANK_1;
  sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_2CYCLES_5;
  sConfigInjected.InjectedSingleDiff = ADC_SINGLE_ENDED;
  sConfigInjected.InjectedOffsetNumber = ADC_OFFSET_NONE;
  sConfigInjected.InjectedOffset = 0;
  sConfigInjected.InjectedNbrOfConversion = 2;
  sConfigInjected.InjectedDiscontinuousConvMode = DISABLE;
  sConfigInjected.AutoInjectedConv = DISABLE;
  sConfigInjected.QueueInjectedContext = DISABLE;
  sConfigInjected.ExternalTrigInjecConv = ADC_EXTERNALTRIGINJEC_T1_TRGO;
  sConfigInjected.ExternalTrigInjecConvEdge = ADC_EXTERNALTRIGINJECCONV_EDGE_RISING;
  sConfigInjected.InjecOversamplingMode = DISABLE;
  if (HAL_ADCEx_InjectedConfigChannel(&hadc1, &sConfigInjected) != HAL_OK)
  {
    Error_Handler();
  }

  /** Configure Injected Channel
  */
  sConfigInjected.InjectedChannel = ADC_CHANNEL_2;
  sConfigInjected.InjectedRank = ADC_INJECTED_RANK_2;
  if (HAL_ADCEx_InjectedConfigChannel(&hadc1, &sConfigInjected) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN ADC1_Init 2 */

 
  HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED);
  HAL_Delay(1);

  ADC1->IER |= ADC_IER_JEOSIE; // Enable end of injected sequence of conversion interrupt
  HAL_ADC_Start(&hadc1);
  ADC1->CR |= ADC_CR_JADSTART; // Enable injected conversions on the selected trigger

  /* USER CODE END ADC1_Init 2 */

}

 

1 REPLY 1
TDK
Super User

This sounds like latch-up behavior.

Latch-up - Wikipedia

 

Prevention would depend on where this is occurring. If this is a motor application, strong diodes preventing negative voltages and overvoltages where they shouldn't be can help. Nothing wrong with the circuit shown.

If you feel a post has answered your question, please click "Accept as Solution".