cancel
Showing results for 
Search instead for 
Did you mean: 

How to get the ADC identifier when using DMA?

LSoll.1
Associate II

Hi!!

I am using a STM32F4 Discovery board. I am using the ADC1 and ADC2, both with DMA. I need the conditional to know which ADC was the one that finished reading data. I tried if(hadc->Instance == ADC1) but it only works when DMA is not used.

Could you help me to get the identifier of the ADC when using DMA?

13 REPLIES 13
ssipa.1
Associate II

hello

first i think you should be aware of some thing like configuration

these are the Steps to configure the ADC in the DMA mode.

1. Enable ADC and GPIO clock

2. Set the prescalar in the Common Control Register (CCR)

3. Set the Scan Mode and Resolution in the Control Register 1 (CR1)

4. Set the Continuous Conversion, EOC, and Data Alignment in Control Reg 2 (CR2)

5. Set the Sampling Time for the channels in ADC_SMPRx

6. Set the Regular channel sequence length in ADC_SQR1

7. Set the Respective GPIO PINs in the Analog Mode

Philippe Cherbonnel
ST Employee

Hi @LSoll.1​ ,

Can you describe more the context of your issue ?

Do you mean the ADC instance in IRQ handler callback function ?

If yes, this is a solution (same as you mentionned):

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
  if(hadc->Instance == ADC1)
  {
    ...
  }
  else /* if(hadc->Instance == ADC2) */
  {
    ...
  }
}

Best regards

Philippe

LSoll.1
Associate II

Hello, I am using the falling edge of TIM8 to launch the conversion of ADC1, once the conversion is finished the DMA transfers the data. That works fine, the problem is that I need to get the interrupt from ADC1 to accumulate the data that the DMA transferred and then average it.

This is the ADC configuration:

static void MX_ADC1_Init(void)

{

 /* USER CODE BEGIN ADC1_Init 0 */

 /* USER CODE END ADC1_Init 0 */

 ADC_ChannelConfTypeDef sConfig = {0};

 /* USER CODE BEGIN ADC1_Init 1 */

 /* USER CODE END ADC1_Init 1 */

 /** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion) 

 */

 hadc1.Instance = ADC1;

 hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;

 hadc1.Init.Resolution = ADC_RESOLUTION_12B;

 hadc1.Init.ScanConvMode = ENABLE;

 hadc1.Init.ContinuousConvMode = DISABLE;

 hadc1.Init.DiscontinuousConvMode = DISABLE;

 hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_FALLING;

 hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T8_TRGO;

 hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;

 hadc1.Init.NbrOfConversion = 3;

 hadc1.Init.DMAContinuousRequests = ENABLE;

 hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV;

 if (HAL_ADC_Init(&hadc1) != HAL_OK)

 {

  Error_Handler();

 }

 /** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time. 

 */

 sConfig.Channel = ADC_CHANNEL_4;

 sConfig.Rank = 1;

 sConfig.SamplingTime = ADC_SAMPLETIME_15CYCLES;

 if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)

 {

  Error_Handler();

 }

This is the DMA configuration:

static void MX_DMA_Init(void) 

{

 /* DMA controller clock enable */

 __HAL_RCC_DMA2_CLK_ENABLE();

 /* DMA interrupt init */

 /* DMA2_Stream0_IRQn interrupt configuration */

 HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 0, 0);

 HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);

}

To get the interrupt I was trying the following code:

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc) {

if (hadc->Instance == ADC1) {

}

}

That code works as long as DMA is not used. When enabling the DMA, I notice that the identifier changes when you enter this function

static void ADC_DMAConvCplt(DMA_HandleTypeDef *hdma)  

{

 /* Retrieve ADC handle corresponding to current DMA handle */

 ADC_HandleTypeDef* hadc = ( ADC_HandleTypeDef* )((DMA_HandleTypeDef* )hdma)->Parent; //here change the identifier

  

 /* Update state machine on conversion status if not in error state */

 if (HAL_IS_BIT_CLR(hadc->State, HAL_ADC_STATE_ERROR_INTERNAL | HAL_ADC_STATE_ERROR_DMA))

 {

  /* Update ADC state machine */

  SET_BIT(hadc->State, HAL_ADC_STATE_REG_EOC);

   

  /* Determine whether any further conversion upcoming on group regular  */

  /* by external trigger, continuous mode or scan sequence on going.   */

  /* Note: On STM32F4, there is no independent flag of end of sequence.  */

  /*    The test of scan sequence on going is done either with scan  */

  /*    sequence disabled or with end of conversion flag set to    */

  /*    of end of sequence.                      */

  if(ADC_IS_SOFTWARE_START_REGULAR(hadc)          &&

    (hadc->Init.ContinuousConvMode == DISABLE)      &&

    (HAL_IS_BIT_CLR(hadc->Instance->SQR1, ADC_SQR1_L) || 

    HAL_IS_BIT_CLR(hadc->Instance->CR2, ADC_CR2_EOCS) )  )

  {

   /* Disable ADC end of single conversion interrupt on group regular */

   /* Note: Overrun interrupt was enabled with EOC interrupt in     */

   /* HAL_ADC_Start_IT(), but is not disabled here because can be used  */

   /* by overrun IRQ process below.                   */

   __HAL_ADC_DISABLE_IT(hadc, ADC_IT_EOC);

    

   /* Set ADC state */

   CLEAR_BIT(hadc->State, HAL_ADC_STATE_REG_BUSY);  

    

   if (HAL_IS_BIT_CLR(hadc->State, HAL_ADC_STATE_INJ_BUSY))

   {

    SET_BIT(hadc->State, HAL_ADC_STATE_READY);

   }

  }

   

  /* Conversion complete callback */

#if (USE_HAL_ADC_REGISTER_CALLBACKS == 1)

  hadc->ConvCpltCallback(hadc);

#else

  HAL_ADC_ConvCpltCallback(hadc);

#endif /* USE_HAL_ADC_REGISTER_CALLBACKS */

 }

 else /* DMA and-or internal error occurred */

 {

  if ((hadc->State & HAL_ADC_STATE_ERROR_INTERNAL) != 0UL)

  {

   /* Call HAL ADC Error Callback function */

#if (USE_HAL_ADC_REGISTER_CALLBACKS == 1)

   hadc->ErrorCallback(hadc);

#else

   HAL_ADC_ErrorCallback(hadc);

#endif /* USE_HAL_ADC_REGISTER_CALLBACKS */

  }

else

{

   /* Call DMA error callback */

   hadc->DMA_Handle->XferErrorCallback(hdma);

  }

 }

}

TDK
Guru

>  I tried if(hadc->Instance == ADC1) but it only works when DMA is not used.

>  ADC_HandleTypeDef* hadc = ( ADC_HandleTypeDef* )((DMA_HandleTypeDef* )hdma)->Parent; //here change the identifier

How would this work if DMA isn't used? The hdma structure wouldn't exist.

What does the value equal when DMA is used?

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

I understand that you only enter the ADC_DMAConvCplt() function when DMA is used, right? That's why it works if you don't use it.

After "ADC_HandleTypeDef* hadc = ( ADC_HandleTypeDef* )((DMA_HandleTypeDef* )hdma)->Parent" the value of hadc->Instance is equal to 0xfff

TDK
Guru

Can you attach the full main.c file? Doesn't look like the DMA is being linked to the ADC.

Ensure DMA is initialized before ADC.

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

Agree with @TDK​ , You probably have a problem in the HAL handles usage of your application.

You have to take care about DMA handle: it is a static variable and must be different for each ADC.

For example:

static DMA_HandleTypeDef  hdma_adc1;
static DMA_HandleTypeDef  hdma_adc2;
...
hdma_adc1.Instance = DMA2_Stream0;
hdma_adc1.Init. ...
__HAL_LINKDMA(&hadc1, DMA_Handle, hdma_adc1);
...
...
hdma_adc2.Instance = DMA2_Stream2;
hdma_adc2.Init. ...
__HAL_LINKDMA(&hadc2, DMA_Handle, hdma_adc2);
...

LSoll.1
Associate II

I upload the .main as clean as possible, it only has the configuration. I don't understand what I'm doing wrong.

Please tell me if any other files are missing

Thanks!

Philippe Cherbonnel
ST Employee

Can you also attach file "..._hal_msp.c" ? This is where DMA configuration and handles link is done.