cancel
Showing results for 
Search instead for 
Did you mean: 

STM32L432KC ADC DMA overrun in continous mode and circular buffer

alexrr
Associate II

Hi,

I have several issues trying to run ADC in continous conversion mode with DMA circular buffer. The fact is that is starts to work normally but after a random time adc raise the overrun flag and adc and dma stop running. I´ve tried multiple clock configuration, from feeding the adc with sysclk to use it with pllsai1. Also tested with MSI and HSI. I´ve also tried to run the adc with less frequency than cpu and DMA unsuccessfully. Then i´ve played with sample times and other configurations without any success. I´ve configured the ADC to work with DMA in other chips like the STM32F303K8 or STM32F429ZI, and worked perfectly at full speed. Any help is appreciated, I have no way to find the solution. I attach the code of main and hal_msp files. (NOTE: this is a test program, so HAL_ADC_ConvHalfCpltCallback and HAL_ADC_ConvCpltCallback are not called, but hal interrupt management is configured and they default definitions are called. And I´ve also tryed with them, entering the functions properly, but same overrun issue).

Thank you,

Best Rewards, Alex R.

main.c

#include "main.h"
#define ADC_BUF_LEN 100
 
ADC_HandleTypeDef hadc1;
DMA_HandleTypeDef hdma_adc1;
 
uint16_t adc_buf[ADC_BUF_LEN];
 
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_DMA_Init(void);
static void MX_ADC1_Init(void);
 
int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_ADC1_Init();
 
  HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED);   
  HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_buf, ADC_BUF_LEN);
 
  while (1)
  {
  }
}
 
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
 
  if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK)
  {
    Error_Handler();
  }
 
  HAL_PWR_EnableBkUpAccess();
  __HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_LOW);
 
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE|RCC_OSCILLATORTYPE_MSI;
  RCC_OscInitStruct.LSEState = RCC_LSE_ON;
  RCC_OscInitStruct.MSIState = RCC_MSI_ON;
  RCC_OscInitStruct.MSICalibrationValue = 0;
  RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_6;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_MSI;
  RCC_OscInitStruct.PLL.PLLM = 1;
  RCC_OscInitStruct.PLL.PLLN = 40;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV7;
  RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
  RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
 
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
 
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
  {
    Error_Handler();
  }
 
  HAL_RCCEx_EnableMSIPLLMode();
}
 
static void MX_ADC1_Init(void)
{
  ADC_ChannelConfTypeDef sConfig = {0};
 
  hadc1.Instance = ADC1;
  hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
  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 = DISABLE;
  if (HAL_ADC_Init(&hadc1) != HAL_OK)
  {
    Error_Handler();
  }
 
  sConfig.Channel = ADC_CHANNEL_5;
  sConfig.Rank = ADC_REGULAR_RANK_1;
  sConfig.SamplingTime = ADC_SAMPLETIME_2CYCLES_5;
  sConfig.SingleDiff = ADC_SINGLE_ENDED;
  sConfig.OffsetNumber = ADC_OFFSET_NONE;
  sConfig.Offset = 0;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
}
 
static void MX_DMA_Init(void)
{
  __HAL_RCC_DMA1_CLK_ENABLE();
  HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);
 
}
 
static void MX_GPIO_Init(void)
{
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
 
}
 
void Error_Handler(void)
{
  __disable_irq();
  while (1)
  {
  }
}

stm32l4xx_hal_msp.c

#include "main.h"
 
extern DMA_HandleTypeDef hdma_adc1;
 
void HAL_MspInit(void)
{
  __HAL_RCC_SYSCFG_CLK_ENABLE();
  __HAL_RCC_PWR_CLK_ENABLE();
}
 
void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
  if(hadc->Instance==ADC1)
  {
    PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC;
    PeriphClkInit.AdcClockSelection = RCC_ADCCLKSOURCE_SYSCLK;
    if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
    {
      Error_Handler();
    }
 
    __HAL_RCC_ADC_CLK_ENABLE();
 
    __HAL_RCC_GPIOA_CLK_ENABLE();
 
    GPIO_InitStruct.Pin = GPIO_PIN_0;
    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG_ADC_CONTROL;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
 
    hdma_adc1.Instance = DMA1_Channel1;
    hdma_adc1.Init.Request = DMA_REQUEST_0;
    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_CIRCULAR;
    hdma_adc1.Init.Priority = DMA_PRIORITY_VERY_HIGH;
    if (HAL_DMA_Init(&hdma_adc1) != HAL_OK)
    {
      Error_Handler();
    }
 
    __HAL_LINKDMA(hadc,DMA_Handle,hdma_adc1);
  }
 
}
 
void HAL_ADC_MspDeInit(ADC_HandleTypeDef* hadc)
{
  if(hadc->Instance==ADC1)
  {
    __HAL_RCC_ADC_CLK_DISABLE();
    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_0);
    HAL_DMA_DeInit(hadc->DMA_Handle);
  }
 
}

5 REPLIES 5
alexrr
Associate II

Please, I need help with this issue.

Thank you.

Bob S
Principal

Is that really the entire code that you are running? If so, how are you detecting that the ADC/DMA is no longer running?

What version CubeMX and L4xx HAL library are you using?

alexrr
Associate II

Yes, it's all the code I'm running. I discovered the issue in a bigger application, so I isolated the adc acquisition routine in a simple project to see if it was really the problem. To see the ADC and DMA behaviour I use the keil debugger, so I can see the ADC/DMA flags and registers.

I'm using CubeMX version 6.4.0 with FW_L4 V1.17.2 (latest), L4xx HAL version 1.13.0, and working on keil uVision5 compiler version V5.06 update 7

Piranha
Chief II

Does the overrun happen even without the debugger?

While the issue must be fixed, the device should still recover from the overrun automatically.

alexrr
Associate II

Yes, it happens even without the debugger. The device could recover if I change hadc1.Init.Overrun to ADC_OVR_DATA_OVERWRITTEN, or if I attend to ADC1 interrupt. The point is that sometimes in random moments data is lost. This system is used in a bigger application as part of an FSK receiver, and i'm loosing bits due to this issue. It's not a speed issue so sampling frequency goes around 150KHz in a CPU that can runs up to 80MHz. Also I have tested this simple program and the bigger application in other boards and everything works perfectly. Tested on STM32F429ZI and STM32F303K8, and no overrun occurs, even at maximum ADC speed. And the FSK also works perfect, no one bit lost during hours sending packets.