Skip to main content
mur
Associate III
May 9, 2020
Solved

Example for ADC in multimode with dual DMA?

  • May 9, 2020
  • 4 replies
  • 7165 views

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.

This topic has been closed for replies.
Best answer by mur

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

4 replies

Nikita91
Lead II
May 9, 2020

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
murAuthor
Associate III
May 9, 2020

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
murAuthorBest answer
Associate III
May 11, 2020

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
Associate III
April 27, 2021

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 ?