1
\$\begingroup\$

I am trying to use ADC with 2 channels and DMA, but I only get 1 reading before the overrun bit gets set. Also the 1 reading is wrong, I am expecting a value of approx 2100, but I am getting around 70. I can see in the hadc->DR that the value are correct, but it is not transferred to the array somehow (adc_value in runADC200Hz function below).

here is the code I am using:

main.c

static 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 = ENABLE;
  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_PRESERVED;
  if (HAL_ADC_Init(&hadc) != HAL_OK)
  {
    Error_Handler();
  }
  /** Configure for the selected ADC regular channel to be converted. 
  */
  sConfig.Channel = ADC_CHANNEL_0;
  sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
  sConfig.SamplingTime = ADC_SAMPLETIME_71CYCLES_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_1;
  if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
}

static void MX_DMA_Init(void) 
{

  /* DMA controller clock enable */
  __HAL_RCC_DMA1_CLK_ENABLE();

  /* DMA interrupt init */
  /* DMA1_Channel1_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 3, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);

}

stm32f0xx_hal_msp.c

void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(hadc->Instance==ADC1)
  {

    /* Peripheral clock enable */
    __HAL_RCC_ADC1_CLK_ENABLE();
  
    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**ADC GPIO Configuration    
    PA0     ------> ADC_IN0
    PA1     ------> ADC_IN1 
    */
    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 */
    /* 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_WORD;
    hdma_adc.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
    hdma_adc.Init.Mode = DMA_CIRCULAR;
    hdma_adc.Init.Priority = DMA_PRIORITY_LOW;
    if (HAL_DMA_Init(&hdma_adc) != HAL_OK)
    {
      Error_Handler();
    }

    __HAL_LINKDMA(hadc,DMA_Handle,hdma_adc);

    /* ADC1 interrupt Init */
    HAL_NVIC_SetPriority(ADC1_COMP_IRQn, 5, 0);
    HAL_NVIC_EnableIRQ(ADC1_COMP_IRQn);

  }

}

stm32f0xx_it.c

void DMA1_Channel1_IRQHandler(void)
{
  HAL_DMA_IRQHandler(&hdma_adc);
}

/**
  * @brief This function handles ADC and COMP interrupts (COMP interrupts through EXTI lines 21 and 22).
  */
void ADC1_COMP_IRQHandler(void)
{
  HAL_ADC_IRQHandler(&hadc);
}

I am running the ADC every 5ms like this:

static uint32_t adc_value[2];

void runADC200Hz(void)
{
  if (HAL_ADC_Start_DMA(&hadc, (uint32_t*) &adc_value[0], 2) != HAL_OK){
      asm("nop");
  }
}

After the first conversion these flags are set:

  • ADC ready (ADRDY)
  • End of sampling (EOSMP)
  • End of conversion (EOC)
  • End of sequence (EOS)
  • ADC overrun (OVR)

I have been setting up ADC with DMA several times before with no problems, but that was on F2 and F7. Strange thing is that I have access to another code which works for the exact same chip, with the exact same code I have written above. I have no idea where I should look and compare beyond those functions above. Any suggestion on what Im doing wrong here? I have tried every type of sampletime but it is the same result. thanks for any comments!

\$\endgroup\$
2
  • 1
    \$\begingroup\$ try making your array uint16_t instead of uint32_t \$\endgroup\$
    – Ocanath
    Jun 11, 2020 at 17:54
  • \$\begingroup\$ @Ocanath unfortunately no difference \$\endgroup\$
    – hoddy
    Jun 12, 2020 at 12:03

2 Answers 2

2
\$\begingroup\$

You are repeatedly calling the ADC in DMA mode, yet you have configured it to run continuous conversion mode. Meaning it will never stop sampling, repeating the sequence until stopped.

If your goal is to sample at 200 Hz, change it to these:

hadc.Init.ContinuousConvMode = DISABLE;
hadc.Init.ExternalTrigConv =  ADC_EXTERNALTRIGCONV_T1_xxx;
hadc.Init.ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising;

And configure a timer to trigger the sampling sequence.


I forgot, you also need to qualify adc_value as volatile since it changes outside of the compilers knowledge (the dma changes it).

The static keyword is poorly named and actually means private in this context. It has no effect other than reducing scope.

\$\endgroup\$
6
  • \$\begingroup\$ Thanks for comment. It made no difference unfortunately \$\endgroup\$
    – hoddy
    Jun 12, 2020 at 12:04
  • \$\begingroup\$ My bad, it actually solved the overrun problem, I can now run more iterations, thansk!. But I am still not getting the correct value transfered from DR to my array \$\endgroup\$
    – hoddy
    Jun 12, 2020 at 12:26
  • \$\begingroup\$ @hoddy make it volatile. \$\endgroup\$
    – Jeroen3
    Jun 12, 2020 at 12:55
  • \$\begingroup\$ volatile didn't work. I checked the DMA register and nothing in the CCR1 is getting set, except for the channel enable bit. That's weird because I have checked that the HAL_ADC_MspInit() function is running \$\endgroup\$
    – hoddy
    Jun 12, 2020 at 13:13
  • \$\begingroup\$ @hoddy check if the correct result is written in ADC->DR \$\endgroup\$
    – Jeroen3
    Jun 12, 2020 at 13:42
2
\$\begingroup\$

Regarding "hadc->DR that the value are correct, but it is not transferred to the array": There is a bug from cubeMX. These functions were generated in this order:

  MX_ADC_Init();
  MX_DMA_Init(); 

but they are supposed to be:

  MX_DMA_Init(); 
  MX_ADC_Init();
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.