cancel
Showing results for 
Search instead for 
Did you mean: 

How to correctly read ADC internal channels with DMA

LVolp.2
Associate II

Hello, 

I am using a p-nucleo-WB55 and I am trying to use DMA to read two internal channels : 

- Internal temperature sensor 

- Vbat

Here is my code :

#define VDDA_APPLI                       (3300U)
 
uint16_t ReadVbat(uint16_t value)
{
	return (value/65536)*VDDA_APPLI*3;
}
 
int main(void)
{
     HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED);
 
     uint16_t ADC_Results[2];
     uint16_t ADC_TEMP = 0;
     uint16_t ADC_VBAT = 0;
 
     while (1)
     {
          HAL_ADC_Start_DMA(&hadc1, (uint32_t*)ADC_Results, 2);
	  if (overflow == 1)
	  {
		  ADC_TEMP = __LL_ADC_CALC_TEMPERATURE(VDDA_APPLI, ADC_Results[0], LL_ADC_RESOLUTION_12B);
		  ADC_VBAT = ReadVbat(ADC_Results[1]);
	  }
	  overflow = 0;
          HAL_Delay(100);
     }
}

Here is the configuration of the ADC :

/** Common config
  */
  hadc1.Instance = ADC1;
  hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
  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 = 2;
  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_PRESERVED;
  hadc1.Init.OversamplingMode = DISABLE;
  if (HAL_ADC_Init(&hadc1) != HAL_OK)
  {
    Error_Handler();
  }
 
  /** Configure Regular Channel
  */
  sConfig.Channel = ADC_CHANNEL_TEMPSENSOR;
  sConfig.Rank = ADC_REGULAR_RANK_1;
  sConfig.SamplingTime = ADC_SAMPLETIME_2CYCLES_5;
  sConfig.SingleDiff = ADC_SINGLE_ENDED;
  sConfig.OffsetNumber = ADC_OFFSET_NONE;
  sConfig.Offset = 0;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
 
  /** Configure Regular Channel
  */
  sConfig.Channel = ADC_CHANNEL_VBAT;
  sConfig.Rank = ADC_REGULAR_RANK_2;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }

The value that I get are not good and I think maybe it is a calibration issue

Results :

0693W00000QO42rQAD.png ADC_TEMP should be between 25 and 30 and ADC_VBAT should be at 3300.

Had you once this issue ? Do you know what could be wrong ?

Have a nice day

1 REPLY 1

> uint16_t value

> return (value/65536)*VDDA_APPLI*3;

This is always zero, due to truncating integer division.

> __LL_ADC_CALC_TEMPERATURE

Look at that macro in Cube, check all values in that macro (in headers and subsequently reading out from the system memory), check if the ADC readout value is within the expected range.

JW