Skip to main content
Visitor II
September 22, 2025
Solved

How to use ADC with DMA on the STM32H7S78-DK

  • September 22, 2025
  • 2 replies
  • 443 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 ?

    This topic has been closed for replies.
    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

    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.

    VPguyAuthor
    Visitor II
    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
    Visitor II
    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?

    VPguyAuthorAnswer
    Visitor II
    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.