cancel
Showing results for 
Search instead for 
Did you mean: 

How to use ADC with DMA on the STM32H7S78-DK

VPguy
Associate II

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 ?

1 ACCEPTED SOLUTION

Accepted Solutions
VPguy
Associate II

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.

View solution in original post

4 REPLIES 4
TDK
Super User

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".
VPguy
Associate II

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.

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?

VPguy
Associate II

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.