2020-05-09 05:14 AM
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.
Solved! Go to Solution.
2020-05-11 12:32 AM
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
2020-05-09 09:44 AM
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!
2020-05-09 10:13 AM
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.
2020-05-11 12:32 AM
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
2021-04-27 07:10 AM
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 ?