cancel
Showing results for 
Search instead for 
Did you mean: 

DMA + ADC doesn't work

Stecklo
Senior

CubeIDE 1.1.0

STM32Cube_FW_WB_V1.3.0

Trying to make DMA transfer ADC results.

I'm putting code in main() after MX_..._Init() and before while(1) {}

HAL_ADC_Start_IT(&hadc1); works fine

HAL_DMA_Start_IT(&hdma_memtomem_dma1_channel2, (uint32_t) src, (uint32_t) dest, 40); works fine too

but

HAL_ADC_Start_DMA(&hadc1, dest, 10) doesn't work as it should

ADC is activated and keeps throwing Overrun_Error

But DMA doesn't transfer anything

static void MX_ADC1_Init(void)
{
 
  /* USER CODE BEGIN ADC1_Init 0 */
 
  /* USER CODE END ADC1_Init 0 */
 
  ADC_ChannelConfTypeDef sConfig = {0};
 
  /* USER CODE BEGIN ADC1_Init 1 */
 
  /* USER CODE END ADC1_Init 1 */
  /** Common config 
  */
  hadc1.Instance = ADC1;
  hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV8;
  hadc1.Init.Resolution = ADC_RESOLUTION_12B;
  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
  hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  hadc1.Init.LowPowerAutoWait = DISABLE;
  hadc1.Init.ContinuousConvMode = ENABLE;
  hadc1.Init.NbrOfConversion = 1;
  hadc1.Init.DiscontinuousConvMode = DISABLE;
  hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
  hadc1.Init.DMAContinuousRequests = ENABLE;
  hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED;
  hadc1.Init.OversamplingMode = ENABLE;
  hadc1.Init.Oversampling.Ratio = ADC_OVERSAMPLING_RATIO_16;
  hadc1.Init.Oversampling.RightBitShift = ADC_RIGHTBITSHIFT_NONE;
  hadc1.Init.Oversampling.TriggeredMode = ADC_TRIGGEREDMODE_SINGLE_TRIGGER;
  hadc1.Init.Oversampling.OversamplingStopReset = ADC_REGOVERSAMPLING_CONTINUED_MODE;
  if (HAL_ADC_Init(&hadc1) != HAL_OK)
  {
    Error_Handler();
  }
  /** Configure Regular Channel 
  */
  sConfig.Channel = ADC_CHANNEL_5;
  sConfig.Rank = ADC_REGULAR_RANK_1;
  sConfig.SamplingTime = ADC_SAMPLETIME_2CYCLES_5;
  sConfig.SingleDiff = ADC_DIFFERENTIAL_ENDED;
  sConfig.OffsetNumber = ADC_OFFSET_NONE;
  sConfig.Offset = 0;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN ADC1_Init 2 */
 
  /* USER CODE END ADC1_Init 2 */
 
}
static void MX_DMA_Init(void) 
{
 
  /* DMA controller clock enable */
  __HAL_RCC_DMAMUX1_CLK_ENABLE();
  __HAL_RCC_DMA1_CLK_ENABLE();
 
  /* Configure DMA request hdma_memtomem_dma1_channel2 on DMA1_Channel2 */
  hdma_memtomem_dma1_channel2.Instance = DMA1_Channel2;
  hdma_memtomem_dma1_channel2.Init.Request = DMA_REQUEST_MEM2MEM;
  hdma_memtomem_dma1_channel2.Init.Direction = DMA_MEMORY_TO_MEMORY;
  hdma_memtomem_dma1_channel2.Init.PeriphInc = DMA_PINC_ENABLE;
  hdma_memtomem_dma1_channel2.Init.MemInc = DMA_MINC_ENABLE;
  hdma_memtomem_dma1_channel2.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
  hdma_memtomem_dma1_channel2.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
  hdma_memtomem_dma1_channel2.Init.Mode = DMA_NORMAL;
  hdma_memtomem_dma1_channel2.Init.Priority = DMA_PRIORITY_LOW;
  if (HAL_DMA_Init(&hdma_memtomem_dma1_channel2) != HAL_OK)
  {
    Error_Handler( );
  }
 
  /* DMA interrupt init */
  /* DMA1_Channel1_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 15, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);
 
}
void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(hadc->Instance==ADC1)
  {
  /* USER CODE BEGIN ADC1_MspInit 0 */
 
  /* USER CODE END ADC1_MspInit 0 */
    /* Peripheral clock enable */
    __HAL_RCC_ADC_CLK_ENABLE();
  
    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**ADC1 GPIO Configuration    
    PA0     ------> ADC1_IN5
    PA1     ------> ADC1_IN6 
    */
    GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1;
    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
 
    /* ADC1 DMA Init */
    /* ADC1 Init */
    hdma_adc1.Instance = DMA1_Channel1;
    hdma_adc1.Init.Request = DMA_REQUEST_ADC1;
    hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;
    hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
    hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
    hdma_adc1.Init.Mode = DMA_NORMAL;
    hdma_adc1.Init.Priority = DMA_PRIORITY_HIGH;
    if (HAL_DMA_Init(&hdma_adc1) != HAL_OK)
    {
      Error_Handler();
    }
 
    __HAL_LINKDMA(hadc,DMA_Handle,hdma_adc1);
 
  /* USER CODE BEGIN ADC1_MspInit 1 */
 
  /* USER CODE END ADC1_MspInit 1 */
  }
 
}

I've tried this confuguration on PNUCLEO-WB55 Dongle in far more complex code and it worked. Now I'm using custom board and just main() body. But I think the board should not matter as DMA is totally internal thing

25 REPLIES 25
Jim Seymour
Senior

In case it helps, I've just spent the last two days debugging this issue on a STM32F030RC.

In my code (also generated by CubeIDE), MX_DMA_Init() does very little (enables the clock and interrupt handler). Later, MX_ADC_Init() calls HAL_ADC_Init() - which calls HAL_ADC_MspInit() - which calls HAL_DMA_Init().

This last function tries to set the CCR register - but it has no effect. (The register remains zero). I'm guessing this is because __HAL_RCC_DMA1_CLK_ENABLE() hasn't been called (?)

Regardless, if I move MX_DMA_Init() just before MX_ADC_Init(), everything seems to work.

Definitely a bug in CubeIDE - but at least I have a workaround.

One last comment: In my case, adding __HAL_RCC_DMA1_CLK_ENABLE(); to the "USER CODE BEGIN SysInit" block in main() also does the trick.

This fix has the advantage of allowing future code generation cycles without having to manually edit the results.

Hey @Nesrine.JLASSI​ 

This still hasn't been fixed in CubeMX v5.5.0

I spent many hours debugging

gretis
Associate

Now is the end of 2021 and problem still present. Thanks to published resolution!

ad ho
Associate III

How is that possible I get the same bug with same resolution after 2 years??? Come on...!

Amel NASRI
ST Employee

Hi @gretis​  & @Community member​ ,

Problem was fixed, but unfortunately appeared again as a regression with latest STM32CubeMX version (6.3.0).

I assume that it will be fixed in coming version of the tool. @Khouloud OTHMAN​  can confirm about this.

Sorry for such inconvenience.

-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.

Thanks for the fast confirmation! at least this is reassuring :)

good day to you

Hey @Nesrine.JLASSI (ST Employee)​,

had still the same issue in CubeMX 6.3.0-RC5 in CubeIDE 1.7.0.

Glad I found this thread!

Best regards,

Peter

eg7963
Associate III

This is still true at this time.

Lost a couple hours figuring out why a previous program was working ( where i already applied the correction and already lost couple hours a few months ago figuring out why the SPI wasn't working) and not the last one i generated with nearly same code but differnet MCU. Luckily i came accros that thread that reminded me the fix I made in the previous program.

Used the latest STM32CubeMX V6.3.0 and latest definition for STM32H7 MCUs.

The easiest way to avoid that to happen when knowing the problem is by sorting the init function in STM32CubeMX>ProjectManager> Advanced Settings

Otherwise the problem reappears by each new regeneration of the project

I have this board:

NUCLEO-L452RE

I used this:

STM32CubeIDE

Version: 1.8.0

Build: 11526_20211125_0815 (UTC)

I followed this tutorial

Getting Started with STM32 - Working with ADC and DMA (digikey.com)

I only got one value in the adc_buf, never more.

I swapped the order of inits and it works, but breaks again each time I redo the IOC file.

The issue still exists, please help.