1

I will give you some context about what I am doing and my problem:

I am using an STM32H723zg board to read and process analog data coming from a sensor. This is an image sensor working at 8 MHz and it sends the pixel values as pulses with an analog amplitude. This sensor also provides a trigger signal because the pixel data should be sampled in the rising edge of the trigger signal (see image below, where the video signal are the pulses with analog amplitude).

enter image description here

Based on the STM32H723zg datasheet, a single ADC can't sample at 8 MSPS. That is why I decided to use two ADCs at 4 MHz to sample the complete data. The idea is to use another 4 MHz clock such that the rising edge and the falling edge of the 4 MHz clock coincide with the rising edge of the 8 MHz clock. In this case, I can sample the video pulses in the rising and falling edge in the following way:

  • ADC1 would sample on the rising edge by using this 4 MHz clock as an external trigger
  • ADC2 would sample on the falling edge by using this 4 MHz clock as an external trigger too.

Both ADCs are using independent DMAs to store their data. When I test this configuration, I get the pattern that I am expecting to see in both ADCs, but it seems that the data from the ADC2 has an offset in comparison with the data from the ADC1.

Even when both ADCs have the pattern of the sampled signal, both produce different values (as if one had an offset and the other did not). Can you help me to undestand why this happens and how to get similar values in both ADCs? I will put my configuration and code below:

The configuration for the ADC1:

  hadc1.Instance = ADC1;
  hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
  hadc1.Init.Resolution = ADC_RESOLUTION_12B;
  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_EXTERNALTRIG_EXT_IT11;
  hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING;
  hadc1.Init.ConversionDataManagement = ADC_CONVERSIONDATA_DMA_ONESHOT;
  hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED;
  hadc1.Init.LeftBitShift = ADC_LEFTBITSHIFT_NONE;
  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 Regular Channel
  */
  sConfig.Channel = ADC_CHANNEL_4;
  sConfig.Rank = ADC_REGULAR_RANK_1;
  sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
  sConfig.SingleDiff = ADC_SINGLE_ENDED;
  sConfig.OffsetNumber = ADC_OFFSET_NONE;
  sConfig.Offset = 0;
  sConfig.OffsetSignedSaturation = DISABLE;
    

The configuration for the ADC2:

  hadc2.Instance = ADC2;
  hadc2.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
  hadc2.Init.Resolution = ADC_RESOLUTION_12B;
  hadc2.Init.ScanConvMode = ADC_SCAN_DISABLE;
  hadc2.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  hadc2.Init.LowPowerAutoWait = DISABLE;
  hadc2.Init.ContinuousConvMode = DISABLE;
  hadc2.Init.NbrOfConversion = 1;
  hadc2.Init.DiscontinuousConvMode = DISABLE;
  hadc2.Init.ExternalTrigConv = ADC_EXTERNALTRIG_EXT_IT11;
  hadc2.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_FALLING;
  hadc2.Init.ConversionDataManagement = ADC_CONVERSIONDATA_DMA_ONESHOT;
  hadc2.Init.Overrun = ADC_OVR_DATA_PRESERVED;
  hadc2.Init.LeftBitShift = ADC_LEFTBITSHIFT_NONE;
  hadc2.Init.OversamplingMode = DISABLE;
  if (HAL_ADC_Init(&hadc2) != HAL_OK)
  {
    Error_Handler();
  }

  /** Configure Regular Channel
  */
  sConfig.Channel = ADC_CHANNEL_4;
  sConfig.Rank = ADC_REGULAR_RANK_1;
  sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
  sConfig.SingleDiff = ADC_SINGLE_ENDED;
  sConfig.OffsetNumber = ADC_OFFSET_NONE;
  sConfig.Offset = 0;
  sConfig.OffsetSignedSaturation = DISABLE;

In the main I calibrate the ADC1 and I use the respective calibration parameters in the ADC2:

  HAL_ADCEx_Calibration_Start(&hadc1,  ADC_CALIB_OFFSET_LINEARITY, ADC_SINGLE_ENDED);
  calibFactor = HAL_ADCEx_Calibration_GetValue(&hadc1, ADC_SINGLE_ENDED);
  HAL_ADCEx_Calibration_SetValue(&hadc2, ADC_SINGLE_ENDED, calibFactor);

Then I enable and start the ADCs. As both ADCs use the same calibration parameter, both uses the same channel (and pin) to sample the data and they have a similar configuration. I don't know why their sampled values are that different. I have not found anything very useful in the documentation related to this problem.

ocrdu
  • 8,705
  • 21
  • 30
  • 42
Carlos T
  • 33
  • 4
  • 2
    My advice is that working around the shortcomings of your platform can be a serious mistake over identifying the platform you need and switching to it. – Scott Seidman Feb 07 '23 at 17:17
  • 2
    I don’t think that applying the calibration values for adc1 to adc2 is correct. I would calibrate them independently. – Bryan Feb 07 '23 at 18:04
  • If you were supposed to apply the same calibration parameters to both ADC1 and ADC2, then the calibration registers would be members of the "ADC Common Registers" set. But they're not, so you need to perform individual calibration on each ADC. – brhans Feb 07 '23 at 18:39

0 Answers0