cancel
Showing results for 
Search instead for 
Did you mean: 

ADC + DMA - multiple channels filled into buffer in wrong order?

TMcCa.1
Associate II

Hi,

I am setting up my STM32F405RG with 3 analog inputs on ADC with DMA.

The problem I'm having is that the ADC buffer is being filled in the wrong order:

For example, I have channel 11, 12 and 13, with ranks 1, 2 and 3 respectively, so I presume the ADC buffer should be as follows:

adc_buf[0] -> data from channel 11

adc_buf[1] -> data from channel 12

adc_buf[2] -> data from channel 13

.

.

.

but what I am actually getting is:

adc_buf[0] -> data from channel 12 - this wrong order

adc_buf[1] -> data from channel 11 - this wrong order

adc_buf[2] -> data from channel 13

adc_buf is defined above int main():

#define ADC_BUF_LEN 3
 
uint16_t adc_buf[ADC_BUF_LEN];
 

in int main we have:

int main(void)
{
  /* USER CODE BEGIN 1 */
  /* USER CODE END 1 */
 
  /* MCU Configuration--------------------------------------------------------*/
 
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();
 
  /* USER CODE BEGIN Init */
  /* USER CODE END Init */
 
  /* Configure the system clock */
  SystemClock_Config();
 
  /* USER CODE BEGIN SysInit */
  app_init();
  /* USER CODE END SysInit */
 
  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_ADC1_Init();
  MX_I2C1_Init();
  MX_SPI1_Init();
  MX_TIM1_Init();
  MX_USART1_UART_Init();
  MX_USART2_UART_Init();
  MX_USB_DEVICE_Init();
  MX_TIM2_Init();
  MX_TIM3_Init();
  /* USER CODE BEGIN 2 */
  HAL_ADC_Start_DMA(&hadc1, (uint32_t*)&adc_buf[0], ADC_BUF_LEN);
  /* USER CODE END 2 */
 
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
 
	/* Infinite loop */
	/* USER CODE BEGIN WHILE */
 
 
	while (1) {
            //do stuff
	}
    /* USER CODE END WHILE */
    /* USER CODE BEGIN 3 */
  /* USER CODE END 3 */
}

ADC init and DMA init look like this:

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 */
  /** 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 = ENABLE;
  hadc1.Init.DiscontinuousConvMode = DISABLE;
  hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
  hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  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_11;
  sConfig.Rank = 1;
  sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
  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_12;
  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_13;
  sConfig.Rank = 3;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN ADC1_Init 2 */
 
  HAL_ADC_Start(&hadc1);
 
  /* USER CODE END ADC1_Init 2 */
 
}
 
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);
 
}

And when I run I am inspecting the values here:

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
  HAL_GPIO_WritePin(IND1_GPIO_Port, IND1_Pin, 0);
  uint16_t num1, num2, num3 = 0;
  num1 = adc_buf[0]; // should be data from ch11 but is actually ch12
  num2 = adc_buf[1]; // should be data from ch12 but is actually ch11
  num3 = adc_buf[2]; // channel 13
}

Currently I can get all the correct data but I would love to know why the order is incorrect when the adc_buf is being filled.

Thanks!

1 ACCEPTED SOLUTION

Accepted Solutions
I agree with you. They are converted in rank order. But how did you determine they're in the wrong order? I understand you're correlating readings with channels, but you've provided no evidence to back up why you think they're wrong. What are the readings, and how are those pins connected.
Obviously what I'm chasing is the order may in fact be correct, but your assumptions are wrong.
*> HAL_ADC_Start(&hadc1);*
This is also probably causing issues, probably the source of the problem.
You shouldn't start a peripheral twice.
If you feel a post has answered your question, please click "Accept as Solution".

View solution in original post

5 REPLIES 5
TDK
Guru

How do you know it's in the wrong order? Note that 3 cycles is not a long time. The readings might not be what you're expecting, particularly if you're measuring high impedance signals.

If you feel a post has answered your question, please click "Accept as Solution".
TMcCa.1
Associate II

Well, correct me if I'm wrong, but I am presuming that because I set the rank for each ADC channel, that this is the order in which they are scanned and thus the order that they are filled into the buffer?

I agree with you. They are converted in rank order. But how did you determine they're in the wrong order? I understand you're correlating readings with channels, but you've provided no evidence to back up why you think they're wrong. What are the readings, and how are those pins connected.
Obviously what I'm chasing is the order may in fact be correct, but your assumptions are wrong.
*> HAL_ADC_Start(&hadc1);*
This is also probably causing issues, probably the source of the problem.
You shouldn't start a peripheral twice.
If you feel a post has answered your question, please click "Accept as Solution".

Ah yes, sorry... I am running in debug mode and have set a breakpoint where I set num1, num2 and num3 in the HAL_ADC_ConvCpltCallback function.

I have set the three channels to known values: 3.3V , 1.5v and 0V, so I can make sure what the the ADC is reading is correct.

Thanks so much! Yes, this has solved my problem! :smiling_face_with_smiling_eyes:

It looks like starting it twice caused the order to be incorrect!

Thank you for your help.