cancel
Showing results for 
Search instead for 
Did you mean: 

"HAL_ADC_Start_DMA()" - init MSP bug

David Martins
Senior

I am working on a STM32f030.

I need to convert 2 channels of ADC, and decided to use DMA.

After reading the "HAL ADC Generic Driver" - UM1785 section, I got the idea that I don't have to use the "HAL_ADC_MspInit ()" function.

However, nothing works until I call this function again.

The following code is only for debugging and demonstrating the idea. Don't mind the rawness of it.

Do not work:

volatile uint16_t ADC_DMA[2] =
    { 0 };
 
    uint32_t timeout_ms;
 
    while (1)
    {
        timeout_ms = HAL_GetTick() + 50;
 
        adc_conv_done_flag = 0;
 
        HAL_ADC_Start_DMA(&hadc, (uint32_t*) ADC_DMA, 2);
        while (adc_conv_done_flag == 0)
        {
            if (HAL_GetTick() > timeout_ms)
                break;
        }
        HAL_ADC_Stop(&hadc);
 
        HAL_Delay(500);
    }

It works:

volatile uint16_t ADC_DMA[2] =
    { 0 };
 
    uint32_t timeout_ms;
	
	HAL_ADC_MspInit(&hadc);
 
    while (1)
    {
        timeout_ms = HAL_GetTick() + 50;
 
        adc_conv_done_flag = 0;
 
        HAL_ADC_Start_DMA(&hadc, (uint32_t*) ADC_DMA, 2);
        while (adc_conv_done_flag == 0)
        {
            if (HAL_GetTick() > timeout_ms)
                break;
        }
        HAL_ADC_Stop(&hadc);
 
        HAL_Delay(500);
    }

PS: adc_conv_done_flag is set on "HAL_ADC_ConvCpltCallback()" function.

Something here is not working as it should ... I've already lost a few hours following the ST documentation.

1 ACCEPTED SOLUTION

Accepted Solutions
David Martins
Senior

I found that if you call "MX_ADC_Init()" and then "MX_DMA_Init()" (like the order created by the CubeMX) result in the problem reported.

If you change the order, the problem is solved...

So I think that it is a good idea the CubeMX team start to think in th best order to put the config functions after the code generation.

Problem:

MX_ADC_Init();
MX_DMA_Init();

No problem:

MX_DMA_Init();
MX_ADC_Init();

View solution in original post

11 REPLIES 11
David Martins
Senior

Some initialization code...

/* ADC init function */
void MX_ADC_Init(void)
{
  ADC_ChannelConfTypeDef sConfig = {0};
 
  /** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion) 
  */
  hadc.Instance = ADC1;
  hadc.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
  hadc.Init.Resolution = ADC_RESOLUTION_12B;
  hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD;
  hadc.Init.EOCSelection = ADC_EOC_SEQ_CONV;
  hadc.Init.LowPowerAutoWait = DISABLE;
  hadc.Init.LowPowerAutoPowerOff = DISABLE;
  hadc.Init.ContinuousConvMode = DISABLE;
  hadc.Init.DiscontinuousConvMode = DISABLE;
  hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
  hadc.Init.DMAContinuousRequests = ENABLE;
  hadc.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
  if (HAL_ADC_Init(&hadc) != HAL_OK)
  {
    Error_Handler();
  }
  /** Configure for the selected ADC regular channel to be converted. 
  */
  sConfig.Channel = ADC_CHANNEL_13;
  sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
  sConfig.SamplingTime = ADC_SAMPLETIME_55CYCLES_5;
  if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /** Configure for the selected ADC regular channel to be converted. 
  */
  sConfig.Channel = ADC_CHANNEL_VREFINT;
  if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
 
}
 
void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle)
{
 
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(adcHandle->Instance==ADC1)
  {
  /* USER CODE BEGIN ADC1_MspInit 0 */
 
  /* USER CODE END ADC1_MspInit 0 */
    /* ADC1 clock enable */
    __HAL_RCC_ADC1_CLK_ENABLE();
  
    __HAL_RCC_GPIOC_CLK_ENABLE();
    /**ADC GPIO Configuration    
    PC3     ------> ADC_IN13 
    */
    GPIO_InitStruct.Pin = PRESS_SENS_Pin;
    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(PRESS_SENS_GPIO_Port, &GPIO_InitStruct);
 
    /* ADC1 DMA Init */
    /* ADC Init */
    hdma_adc.Instance = DMA1_Channel1;
    hdma_adc.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_adc.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_adc.Init.MemInc = DMA_MINC_ENABLE;
    hdma_adc.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
    hdma_adc.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
    hdma_adc.Init.Mode = DMA_CIRCULAR;
    hdma_adc.Init.Priority = DMA_PRIORITY_MEDIUM;
    if (HAL_DMA_Init(&hdma_adc) != HAL_OK)
    {
      Error_Handler();
    }
 
    __HAL_DMA1_REMAP(HAL_DMA1_CH1_ADC);
 
    __HAL_LINKDMA(adcHandle,DMA_Handle,hdma_adc);
 
  /* USER CODE BEGIN ADC1_MspInit 1 */
 
  /* USER CODE END ADC1_MspInit 1 */
  }
}

Anyone have some idea of why I need to call "HAL_ADC_MspInit()" again? Or why the call inside the "HAL_ADC_Init()" isn't take effect?

David Martins
Senior

I found that if you call "MX_ADC_Init()" and then "MX_DMA_Init()" (like the order created by the CubeMX) result in the problem reported.

If you change the order, the problem is solved...

So I think that it is a good idea the CubeMX team start to think in th best order to put the config functions after the code generation.

Problem:

MX_ADC_Init();
MX_DMA_Init();

No problem:

MX_DMA_Init();
MX_ADC_Init();

OPera
Associate II

Got the same issue with a STM32F769, with DMA UART / I2C.

Moving the MX_DMA_Init() before the ADC and the I2C init solved the issue...

It seems to be an issue with the code generation from STM32CubeMX (last version, embedded in STM32CubeIDE).

Amel NASRI
ST Employee

Yes, indeed it is an issue with STM32CubeMX generated code and it is already reported internally and confirmed to be fixed in next version of the tool (https://community.st.com/s/question/0D50X0000BbMcnpSQC/dma-adc-doesnt-work).

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

ATrev
Associate II

I too am turning to DMA for ADC and have been trying all this morning without success on L552. Then I used the inversion of initializations proposed by Martins. Now things start working.

Many thanks.

Coratron
Associate II

I am glad a stumbled across this post.

2 years on since it was reported and it is still not fixed. Not sure if it was fixed as per what @Amel NASRI​ said and then the bug made it back?

Using STM32G071 nucleo and STM32CubeMX 6.3.0

Coratron
Associate II

After some extra research I have found that it is possible to rearrange the order of the initialising functions under:

Project Manager > Advanced Settings

The top right icons let you move the individual functions up and down which is the order in which they will be generated in main.c

It's not perfect because the default order is still going to cause people to waste hours until they figure it out, but at least it automates the process once the issue is identified.

I hope this will help someone.

0693W00000FDXbkQAH.png

STM employees seem to have zero interest in getting the bugs in their code fixed, and I guess their manager also is not interested. Bad business policy for sure.

Hi @Robmar​ ,

May I understand what are the facts of such conclusion? Are you facing the same issue?

Currently, we are at the revision 6.7.0 of STM32CubeMX. Unfortunately some regressions occurred in previous releases, but this particular issue should be already fixed with current release. This was managed on case by case, in the limit of our capacity to answer the great number of questions.

At that time, and seeing that several of our Customers are facing the same issue, the problem was already recognized and a workaround was suggested by @Khouloud OTHMAN​  in MX_DMA_Init order in the main.c file generated by STM32CubeMX, How to fix?

As already said, now this should be already fixed. But if you think that a particular case isn't covered by this fix, it will be helpful for us to know it.

-Amel

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.