cancel
Showing results for 
Search instead for 
Did you mean: 

Example for ADC in multimode with dual DMA?

mur
Associate III

Hi,

I want to use the simulataneous ADC reading with 2 DMA channels, in order to avoid overrun errors (which I'm having).

I'm using the HAL and I'm having a hard time understanding when is the DMA buffer of the slave channel assigned. When multimode is used, all the manuals and explanations I've seen recommed this structure:

 if (HAL_ADC_Start(&hadc2) != HAL_OK)   Error_Handler();
 
 
 if (HAL_ADCEx_MultiModeStart_DMA(&hadc1, getDMAADCBufferPointer(), ADC_BUFFER_LENGTH) != HAL_OK)     Error_Handler();

Where the slave is started first, but then you are not able to tell the system to use the slave DMA buffer. If I use the same ADC for both, the sampling, transmission to DMA and all happen correctly. But using different DMA channels, I can see the DR registers of the ADC being updated, but the DMA interrupt (HAL_ADC_ConvCpltCallback) does not happen.

The interrupt mapping is:

/**
  * @brief This function handles DMA1 channel1 global interrupt.
  */
void DMA1_Channel1_IRQHandler(void)
{
  /* USER CODE BEGIN DMA1_Channel1_IRQn 0 */
 
  /* USER CODE END DMA1_Channel1_IRQn 0 */
  HAL_DMA_IRQHandler(&hdma_adc1);
  /* USER CODE BEGIN DMA1_Channel1_IRQn 1 */
 
  /* USER CODE END DMA1_Channel1_IRQn 1 */
}
 
/**
  * @brief This function handles DMA1 channel2 global interrupt.
  */
void DMA1_Channel2_IRQHandler(void)
{
  /* USER CODE BEGIN DMA1_Channel2_IRQn 0 */
 
  /* USER CODE END DMA1_Channel2_IRQn 0 */
  HAL_DMA_IRQHandler(&hdma_adc2);
  /* USER CODE BEGIN DMA1_Channel2_IRQn 1 */
  /* USER CODE END DMA1_Channel2_IRQn 1 */
}
 
/**
  * @brief This function handles ADC1 and ADC2 interrupts.
  */
void ADC1_2_IRQHandler(void)
{
  /* USER CODE BEGIN ADC1_2_IRQn 0 */
 
  /* USER CODE END ADC1_2_IRQn 0 */
  HAL_ADC_IRQHandler(&hadc1);
  HAL_ADC_IRQHandler(&hadc2);
  /* USER CODE BEGIN ADC1_2_IRQn 1 */
 
  /* USER CODE END ADC1_2_IRQn 1 */
}

So is there any example around of this application or can you solve the doubts (assign the extra DMA buffer and any other information I should consider) I have?

Thanks.

1 ACCEPTED SOLUTION

Accepted Solutions
mur
Associate III

ST support provided the example as:

uint8_t adcbufS[ADCBUFSIZE];
 
uint8_t adcbufM[ADCBUFSIZE];
 
 
 
 
HAL_ADCEx_Calibration_Start(&hadc1,ADC_SINGLE_ENDED);
 
	HAL_ADCEx_Calibration_Start(&hadc2,ADC_SINGLE_ENDED);
 
	
 
 SET_BIT(hadc2.Instance->CFGR, ADC_CFGR_DMAEN); //Enable DMA transfer for ADC slave (ADC12_CCR.MDMA = 0b00 -> MDMA mode disabled)
 
	HAL_DMA_Start(hadc2.DMA_Handle,(uint32_t)&hadc2.Instance->DR, (uint32_t)adcbufS,ADCBUFSIZE); //Start ADC slave DMA 
 
	
 
 SET_BIT(hadc1.Instance->CFGR, ADC_CFGR_DMAEN); //Enable DMA transfer for ADC master (ADC12_CCR.MDMA = 0b00 -> MDMA mode disabled)
 
 HAL_ADCEx_MultiModeStart_DMA(&hadc1,(uint32_t *)adcbufM,ADCBUFSIZE); //Start ADC interleaved mode

Which I tested and works properly with dual DMA

View solution in original post

4 REPLIES 4
Nikita91
Lead II

What MCU are you using ? What is your acquisition frequency?

If you have overrun with one DMA, you should expect to be having more with 2 DMAs fighting for the same bus...

This may be the reason why ST has planned to use 1 single DMA to acquire data from 2 ADCs!

mur
Associate III

I'm using a stm32f334. I'm sampling every 50us or at 20kHz.

I want to use the double DMA approach as ST suggests in their errata document https://www.st.com/resource/en/errata_sheet/dm00115957-stm32f334x4x6x8-rev-z-device-limitations-stmicroelectronics.pdf. I think I might be experiencing the first explained issue with the ADC sampling in dual simulataneous mode. I also created a post on that issue which you can find https://community.st.com/s/feed/0D53W000006FASl?t=1588930836752.

mur
Associate III

ST support provided the example as:

uint8_t adcbufS[ADCBUFSIZE];
 
uint8_t adcbufM[ADCBUFSIZE];
 
 
 
 
HAL_ADCEx_Calibration_Start(&hadc1,ADC_SINGLE_ENDED);
 
	HAL_ADCEx_Calibration_Start(&hadc2,ADC_SINGLE_ENDED);
 
	
 
 SET_BIT(hadc2.Instance->CFGR, ADC_CFGR_DMAEN); //Enable DMA transfer for ADC slave (ADC12_CCR.MDMA = 0b00 -> MDMA mode disabled)
 
	HAL_DMA_Start(hadc2.DMA_Handle,(uint32_t)&hadc2.Instance->DR, (uint32_t)adcbufS,ADCBUFSIZE); //Start ADC slave DMA 
 
	
 
 SET_BIT(hadc1.Instance->CFGR, ADC_CFGR_DMAEN); //Enable DMA transfer for ADC master (ADC12_CCR.MDMA = 0b00 -> MDMA mode disabled)
 
 HAL_ADCEx_MultiModeStart_DMA(&hadc1,(uint32_t *)adcbufM,ADCBUFSIZE); //Start ADC interleaved mode

Which I tested and works properly with dual DMA

rclar.6
Senior

I have an STM32F446RE working ONCE in HAL_ADCEx_MultiModeStart_DMA and then it seems impossible to trigger again!

Is these something that need sto be cleared down ?