AnsweredAssumed Answered

HAL ADC + DMA Normal Mode Issues

Question asked by Eduardo Campos on Sep 12, 2017

Hi.

I've been working on an application based on STM32F4 (Nucleo-F446RE) and CubeMX + SW4STM32.

The aim of this application is measure multiple electrical signals connected to the ADC's channels in order to obtain their waveform.

 

These signals have a range of 0-3.3V, they aren't continuous and only last for a few ms.

All the input signals start at the same time, and the μc must be able to detect the beginning of the transmission (either by monitoring one ADC channel or by an external logic input syncrhonized with the signal trigger).

Once the A/D conversion starts, a certain number of time spaced sample must be taken for each channel.

 

To achieve this objective, in my opinion the best configuration is:

·Timer triggered ADC in Scanmode (regular conversions) + DMA in normal mode.

(Time between samples >> ADC Conversion time).

 

At this stage i haven't got the code related to de μc's detection of the beginning of the transmission, i'm just trying to obtain a working code to measure the signal and fill a data array once the user button of the nucleo board is pressed.

 

I'm calling the HAL_ADC_Start_DMA() and the HAL_TIM_Base_Start() functions when the button is pressed. The first time i use the ADC_DMA function, the buffer fills up without errors (positions fill up with the expected values of the adc channels: ch1(i), ch2(i), ch3(i), ch1(i), ch2(i)...), where 'i' is the sampling session.

However when i call again HAL_ADC_Start_DMA() function, the buffer values aren't correct, the look shifted of their original position, something like:  (ch1(i) ,ch1(i+1) ,ch2(i+1), ch3(i+1), ch1(i+1), ch2(i+1), ch3(i+1), ch1(i+1)...).

 

Searching for a logic explanation, using debug mode , i've noticed that when the ADC EOC IT callbackFunction happens once the DMA buffer is filled with the defined size, the Status register 'SR' of the ADC has this value 110010. (Overrun and EOC bits are set), and the ADC->DR has a value of ch1.

I believe the last ADC conversion remains there until DMA request are available again and take the value. This would explain why the buffer looks shifted. I've tryed DMA in circular mode and the buffer values are always right, so im pretty sure this is the problem.

 

i've tryed differents things:  CLR  flags, de initialize and re-initialize the ADC but didn't work... I'm not an expert.

 

In brief, my main issue is that once the ADC + DMA are configured, i must be able to launch the signal sampling process everytime i need it and obtain correct values, in correct positions of the buffer.

 

i'm open to suggestions about new ways to face the problem and achive the objective.

 

Thank you for your time

 

Here is the code ------------------------------------------

 

[][]******** main.c ************[][]

 

#include "main.h"
#include "stm32f4xx_hal.h"

 

/* USER CODE BEGIN Includes */

 

#include"lcd_hd44780.h"

 

/* USER CODE END Includes */

 

/* Private variables ---------------------------------------------------------*/
ADC_HandleTypeDef hadc1;
DMA_HandleTypeDef hdma_adc1;

 

TIM_HandleTypeDef htim2;

 

/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/

 

/* USER CODE END PV */

 

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
void Error_Handler(void);
static void MX_GPIO_Init(void);
static void MX_DMA_Init(void);
static void MX_TIM2_Init(void);
static void MX_ADC1_Init(void);

 

/* USER CODE BEGIN PFP */
/* Private function prototypes -----------------------------------------------*/

 

/* USER CODE END PFP */

 

/* USER CODE BEGIN 0 */

 

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
  if(hadc->Instance == ADC1)
  {
    HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);

  }
}

 

/* USER CODE END 0 */

 

int main(void)
{

 

  /* USER CODE BEGIN 1 */
  __IO uint16_t Dma_Buff[60];

 

  for(int i = 0; i < 60; i++)
  {
    Dma_Buff[i] = 0;
  }

 


  /* USER CODE END 1 */

 

  /* MCU Configuration----------------------------------------------------------*/

 

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

 

  /* Configure the system clock */
  SystemClock_Config();

 

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_TIM2_Init();
  MX_ADC1_Init();

 

  /* USER CODE BEGIN 2 */

 

  lcd_init();
  /* USER CODE END 2 */

 

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  lcd_cls();
  lcd_strxy((unsigned char *)"RDY!",0,0);

 

  while (1)
  {
    if(HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13) == 0)
    {
      lcd_cls();
      lcd_strxy((unsigned char *)"1s to Sampling!",0,0);
      HAL_Delay(1000);

 

      lcd_cls();
      lcd_strxy((unsigned char *)"Sampling!",0,0);

 


      HAL_ADC_Start_DMA(&hadc1, (uint32_t*)&Dma_Buff, 60);
      HAL_TIM_Base_Start(&htim2);
    }


  /* USER CODE END WHILE */

 

  /* USER CODE BEGIN 3 */

 

  }
  /* USER CODE END 3 */

}

 

/** System Clock Configuration
*/
void SystemClock_Config(void)
{

 

  RCC_OscInitTypeDef RCC_OscInitStruct;
  RCC_ClkInitTypeDef RCC_ClkInitStruct;

 

    /**Configure the main internal regulator output voltage
    */
  __HAL_RCC_PWR_CLK_ENABLE();

 

  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

 

    /**Initializes the CPU, AHB and APB busses clocks
    */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = 16;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLM = 8;
  RCC_OscInitStruct.PLL.PLLN = 144;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 2;
  RCC_OscInitStruct.PLL.PLLR = 2;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

 

    /**Initializes the CPU, AHB and APB busses clocks
    */
  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_DIV4;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;

 

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
  {
    Error_Handler();
  }

 

    /**Configure the Systick interrupt time
    */
  HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);

 

    /**Configure the Systick
    */
  HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);

 

  /* SysTick_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}

 

/* ADC1 init function */
static void MX_ADC1_Init(void)
{

 

  ADC_ChannelConfTypeDef sConfig;

 

    /**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
    */
  hadc1.Instance = ADC1;
  hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2;
  hadc1.Init.Resolution = ADC_RESOLUTION_12B;
  hadc1.Init.ScanConvMode = ENABLE;
  hadc1.Init.ContinuousConvMode = DISABLE;
  hadc1.Init.DiscontinuousConvMode = DISABLE;
  hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING;
  hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T2_TRGO;
  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc1.Init.NbrOfConversion = 3;
  hadc1.Init.DMAContinuousRequests = ENABLE;
  hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  if (HAL_ADC_Init(&hadc1) != HAL_OK)
  {
    Error_Handler();
  }

 

    /**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
    */
  sConfig.Channel = ADC_CHANNEL_0;
  sConfig.Rank = 1;
  sConfig.SamplingTime = ADC_SAMPLETIME_15CYCLES;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }

 

    /**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
    */
  sConfig.Channel = ADC_CHANNEL_1;
  sConfig.Rank = 2;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }

 

    /**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
    */
  sConfig.Channel = ADC_CHANNEL_4;
  sConfig.Rank = 3;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }

 

}

 

/* TIM2 init function */
static void MX_TIM2_Init(void)
{

 

  TIM_ClockConfigTypeDef sClockSourceConfig;
  TIM_MasterConfigTypeDef sMasterConfig;

 

  htim2.Instance = TIM2;
  htim2.Init.Prescaler = 71;
  htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim2.Init.Period = 49;
  htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
  {
    Error_Handler();
  }

 

  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }

 

  sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }

 

}

 

/**
  * Enable DMA controller clock
  */
static void MX_DMA_Init(void)
{
  /* DMA controller clock enable */
  __HAL_RCC_DMA2_CLK_ENABLE();

 

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

 

}

 

/** Configure pins as
        * Analog
        * Input
        * Output
        * EVENT_OUT
        * EXTI
*/
static void MX_GPIO_Init(void)
{

 

  GPIO_InitTypeDef GPIO_InitStruct;

 

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();

 

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_8|GPIO_PIN_9
                          |GPIO_PIN_10, GPIO_PIN_RESET);

 

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10|GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5, GPIO_PIN_RESET);

 

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_8, GPIO_PIN_RESET);

 

  /*Configure GPIO pin : PC13 */
  GPIO_InitStruct.Pin = GPIO_PIN_13;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

 

  /*Configure GPIO pins : PA5 PA6 PA8 PA9
                           PA10 */
  GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_8|GPIO_PIN_9
                          |GPIO_PIN_10;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

 

  /*Configure GPIO pins : PB10 PB3 PB4 PB5 */
  GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

 

  /*Configure GPIO pin : PC8 */
  GPIO_InitStruct.Pin = GPIO_PIN_8;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

 

}

 

/* USER CODE BEGIN 4 */

 

/* USER CODE END 4 */

 

 

[][][]***** stm32f4xx_hal_msp.c *****[][]

 

#include "stm32f4xx_hal.h"

 

extern DMA_HandleTypeDef hdma_adc1;

 

extern void Error_Handler(void);
/* USER CODE BEGIN 0 */

 

/* USER CODE END 0 */
/**
  * Initializes the Global MSP.
  */
void HAL_MspInit(void)
{
  /* USER CODE BEGIN MspInit 0 */

 

  /* USER CODE END MspInit 0 */

 

  HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_0);

 

  /* System interrupt init*/
  /* MemoryManagement_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(MemoryManagement_IRQn, 0, 0);
  /* BusFault_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(BusFault_IRQn, 0, 0);
  /* UsageFault_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(UsageFault_IRQn, 0, 0);
  /* SVCall_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(SVCall_IRQn, 0, 0);
  /* DebugMonitor_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DebugMonitor_IRQn, 0, 0);
  /* PendSV_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(PendSV_IRQn, 0, 0);
  /* SysTick_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);

 

  /* USER CODE BEGIN MspInit 1 */

 

  /* USER CODE END MspInit 1 */
}

 

void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
{

 

  GPIO_InitTypeDef GPIO_InitStruct;
  if(hadc->Instance==ADC1)
  {
  /* USER CODE BEGIN ADC1_MspInit 0 */

 

  /* USER CODE END ADC1_MspInit 0 */
    /* Peripheral clock enable */
    __HAL_RCC_ADC1_CLK_ENABLE();
 
    /**ADC1 GPIO Configuration    
    PA0-WKUP     ------> ADC1_IN0
    PA1     ------> ADC1_IN1
    PA4     ------> ADC1_IN4
    */
    GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_4;
    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

 

    /* Peripheral DMA init*/
 
    hdma_adc1.Instance = DMA2_Stream0;
    hdma_adc1.Init.Channel = DMA_CHANNEL_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_NORMAL;
    hdma_adc1.Init.Priority = DMA_PRIORITY_LOW;
    hdma_adc1.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    if (HAL_DMA_Init(&hdma_adc1) != HAL_OK)
    {
      Error_Handler();
    }

 

    __HAL_LINKDMA(hadc,DMA_Handle,hdma_adc1);

 

    /* Peripheral interrupt init */
    HAL_NVIC_SetPriority(ADC_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(ADC_IRQn);
  /* USER CODE BEGIN ADC1_MspInit 1 */

 

  /* USER CODE END ADC1_MspInit 1 */
  }

 

}

 

void HAL_ADC_MspDeInit(ADC_HandleTypeDef* hadc)
{

 

  if(hadc->Instance==ADC1)
  {
  /* USER CODE BEGIN ADC1_MspDeInit 0 */

 

  /* USER CODE END ADC1_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_ADC1_CLK_DISABLE();
 
    /**ADC1 GPIO Configuration    
    PA0-WKUP     ------> ADC1_IN0
    PA1     ------> ADC1_IN1
    PA4     ------> ADC1_IN4
    */
    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_4);

 

    /* Peripheral DMA DeInit*/
    HAL_DMA_DeInit(hadc->DMA_Handle);

 

    /* Peripheral interrupt DeInit*/
    HAL_NVIC_DisableIRQ(ADC_IRQn);

 

  }
  /* USER CODE BEGIN ADC1_MspDeInit 1 */

 

  /* USER CODE END ADC1_MspDeInit 1 */

 

}

 

void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base)
{

 

  if(htim_base->Instance==TIM2)
  {
  /* USER CODE BEGIN TIM2_MspInit 0 */

 

  /* USER CODE END TIM2_MspInit 0 */
    /* Peripheral clock enable */
    __HAL_RCC_TIM2_CLK_ENABLE();
  /* USER CODE BEGIN TIM2_MspInit 1 */

 

  /* USER CODE END TIM2_MspInit 1 */
  }

 

}

 

void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* htim_base)
{

 

  if(htim_base->Instance==TIM2)
  {
  /* USER CODE BEGIN TIM2_MspDeInit 0 */

 

  /* USER CODE END TIM2_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_TIM2_CLK_DISABLE();
  }
  /* USER CODE BEGIN TIM2_MspDeInit 1 */

 

  /* USER CODE END TIM2_MspDeInit 1 */

 

}

 

/* USER CODE BEGIN 1 */

 

/* USER CODE END 1 */

Outcomes