Skip to main content
Associate
September 22, 2025
Solved

How to use ADC with DMA on the STM32H7S78-DK

  • September 22, 2025
  • 2 replies
  • 444 views

Hi everyone,

I am currently trying to use the ADC with DMA on my STM32H7S78-DK. To do so, I am following this guide: https://community.st.com/t5/stm32-mcus/stm32h7r-s-how-to-configure-an-adc-dma-transfer-in-circular-mode/ta-p/737149

I've made little changes to the code compared to the guide. I am attaching my project.

 

The problem is that the program ends up in the Error_Handler() when the HAL_ADC_Start_DMA() (or the HAL_ADCEx_Calibration_Start()) function is executed.

During the execution of the HAL_ADC_Start_DMA(), the ADC_Enable() function returns HAL_ERROR:

 /* Enable the ADC peripheral */
 tmp_hal_status = ADC_Enable(hadc);

 /* Start conversion if ADC is effectively enabled */
 if (tmp_hal_status == HAL_OK)

Inside the ADC_Enable() function, the execution lead to this part (ADC_ENABLE_TIMEOUT limit reached):

 if ((HAL_GetTick() - tickstart) > ADC_ENABLE_TIMEOUT)
 {
 /* New check to avoid false timeout detection in case of preemption */
 if (__HAL_ADC_GET_FLAG(hadc, ADC_FLAG_RDY) == 0UL)
 {
 /* Update ADC state machine to error */
 SET_BIT(hadc->State, HAL_ADC_STATE_ERROR_INTERNAL);

 /* Set ADC error code to ADC peripheral internal error */
 SET_BIT(hadc->ErrorCode, HAL_ADC_ERROR_INTERNAL);

 return HAL_ERROR;
 }
 }

I am a bit new to STM32H7S programming and I don't understand why the ADC can't enable.

Do you have any idea ?

Best answer by VPguy

The ADC was in asynchronous mode, the problem was that the PLL didn't launch.

For those who have the same issue, the workaround is to use the synchronous clock source for the ADC.

If I have some time, I will try to see why the PLL was disabled during the execution.

Thanks to the ST support for solving my issue.

2 replies

TDK
Super User
September 22, 2025

Debug the program. When it ends up in Error_Handler, show the stack trace.

 

Actually, step through HAL_ADCEx_Calibration_Start and find out the reason it's returning an error instead of HAL_OK.

"If you feel a post has answered your question, please click ""Accept as Solution""."
VPguyAuthor
Associate
September 22, 2025

How do I do to get the stack trace in STM32CubeIDE?

 

I put some breakpoints in HAL_ADCEx_Calibration_Start and the problem comes from the call to ADC_Enable.

Inside this loop, the program does not enter the first if and ends up in the second one after a certain time:

 while (__HAL_ADC_GET_FLAG(hadc, ADC_FLAG_RDY) == 0UL)
 {
 /* If ADEN bit is set less than 4 ADC clock cycles after the ADCAL bit
 has been cleared (after a calibration), ADEN bit is reset by the
 calibration logic.
 The workaround is to continue setting ADEN until ADRDY is becomes 1.
 Additionally, ADC_ENABLE_TIMEOUT is defined to encompass this
 4 ADC clock cycle duration */
 /* Note: Test of ADC enabled required due to hardware constraint to */
 /* not enable ADC if already enabled. */
 if (LL_ADC_IsEnabled(hadc->Instance) == 0UL)
 {
 LL_ADC_Enable(hadc->Instance);
 }

 if ((HAL_GetTick() - tickstart) > ADC_ENABLE_TIMEOUT)
 {
 /* New check to avoid false timeout detection in case of preemption */
 if (__HAL_ADC_GET_FLAG(hadc, ADC_FLAG_RDY) == 0UL)
 {
 /* Update ADC state machine to error */
 SET_BIT(hadc->State, HAL_ADC_STATE_ERROR_INTERNAL);

 /* Set ADC error code to ADC peripheral internal error */
 SET_BIT(hadc->ErrorCode, HAL_ADC_ERROR_INTERNAL);

 return HAL_ERROR;
 }
 }
 }

 Feel free to ask me for more details, I'm not sure if that's clear.

VPguyAuthor
Associate
September 23, 2025

I searched a bit and find something strange, the HAL_ADC_MspInit() function seems to initialize the DMA with some lines for a linked list:

void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
{
 GPIO_InitTypeDef GPIO_InitStruct = {0};
 DMA_NodeConfTypeDef NodeConfig;
 RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
 if(hadc->Instance==ADC1)
 {
 /* USER CODE BEGIN ADC1_MspInit 0 */

 /* USER CODE END ADC1_MspInit 0 */

 /** Initializes the peripherals clock
 */
 PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC;
 PeriphClkInit.AdcClockSelection = RCC_ADCCLKSOURCE_PLL2P;
 if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
 {
 Error_Handler();
 }

 /* Peripheral clock enable */
 __HAL_RCC_ADC12_CLK_ENABLE();

 __HAL_RCC_GPIOC_CLK_ENABLE();
 __HAL_RCC_GPIOF_CLK_ENABLE();
 /**ADC1 GPIO Configuration
 PC0 ------> ADC1_INP10
 PC2 ------> ADC1_INP12
 PF12 ------> ADC1_INP6
 */
 GPIO_InitStruct.Pin = ADC_A0_Pin|ADC_A1_Pin;
 GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
 GPIO_InitStruct.Pull = GPIO_NOPULL;
 HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

 GPIO_InitStruct.Pin = UCPD1_ISENSE_Pin;
 GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
 GPIO_InitStruct.Pull = GPIO_NOPULL;
 HAL_GPIO_Init(UCPD1_ISENSE_GPIO_Port, &GPIO_InitStruct);

 /* ADC1 DMA Init */
 /* HPDMA1_REQUEST_ADC1 Init */
 NodeConfig.NodeType = DMA_HPDMA_LINEAR_NODE;
 NodeConfig.Init.Request = HPDMA1_REQUEST_ADC1;
 NodeConfig.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;
 NodeConfig.Init.Direction = DMA_PERIPH_TO_MEMORY;
 NodeConfig.Init.SrcInc = DMA_SINC_FIXED;
 NodeConfig.Init.DestInc = DMA_DINC_INCREMENTED;
 NodeConfig.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_HALFWORD;
 NodeConfig.Init.DestDataWidth = DMA_DEST_DATAWIDTH_HALFWORD;
 NodeConfig.Init.SrcBurstLength = 1;
 NodeConfig.Init.DestBurstLength = 1;
 NodeConfig.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT1|DMA_DEST_ALLOCATED_PORT0;
 NodeConfig.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
 NodeConfig.Init.Mode = DMA_NORMAL;
 NodeConfig.TriggerConfig.TriggerPolarity = DMA_TRIG_POLARITY_MASKED;
 NodeConfig.DataHandlingConfig.DataExchange = DMA_EXCHANGE_NONE;
 NodeConfig.DataHandlingConfig.DataAlignment = DMA_DATA_RIGHTALIGN_ZEROPADDED;
 if (HAL_DMAEx_List_BuildNode(&NodeConfig, &Node_HPDMA1_Channel0) != HAL_OK)
 {
 Error_Handler();
 }

 if (HAL_DMAEx_List_InsertNode(&List_HPDMA1_Channel0, NULL, &Node_HPDMA1_Channel0) != HAL_OK)
 {
 Error_Handler();
 }

 if (HAL_DMAEx_List_SetCircularMode(&List_HPDMA1_Channel0) != HAL_OK)
 {
 Error_Handler();
 }

 handle_HPDMA1_Channel0.Instance = HPDMA1_Channel0;
 handle_HPDMA1_Channel0.InitLinkedList.Priority = DMA_LOW_PRIORITY_LOW_WEIGHT;
 handle_HPDMA1_Channel0.InitLinkedList.LinkStepMode = DMA_LSM_FULL_EXECUTION;
 handle_HPDMA1_Channel0.InitLinkedList.LinkAllocatedPort = DMA_LINK_ALLOCATED_PORT0;
 handle_HPDMA1_Channel0.InitLinkedList.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
 handle_HPDMA1_Channel0.InitLinkedList.LinkedListMode = DMA_LINKEDLIST_CIRCULAR;
 if (HAL_DMAEx_List_Init(&handle_HPDMA1_Channel0) != HAL_OK)
 {
 Error_Handler();
 }

 if (HAL_DMAEx_List_LinkQ(&handle_HPDMA1_Channel0, &List_HPDMA1_Channel0) != HAL_OK)
 {
 Error_Handler();
 }

 __HAL_LINKDMA(hadc, DMA_Handle, handle_HPDMA1_Channel0);

 if (HAL_DMA_ConfigChannelAttributes(&handle_HPDMA1_Channel0, DMA_CHANNEL_NPRIV) != HAL_OK)
 {
 Error_Handler();
 }

 /* USER CODE BEGIN ADC1_MspInit 1 */

 /* USER CODE END ADC1_MspInit 1 */

 }

}

 But I did not configure a linked list in CubeMX:

VPguy_0-1758615497026.png

Is my HAL_ADC_MspInit() function incorrect?

VPguyAuthorBest answer
Associate
November 25, 2025

The ADC was in asynchronous mode, the problem was that the PLL didn't launch.

For those who have the same issue, the workaround is to use the synchronous clock source for the ADC.

If I have some time, I will try to see why the PLL was disabled during the execution.

Thanks to the ST support for solving my issue.