cancel
Showing results for 
Search instead for 
Did you mean: 

Troubles with Dual fast multichannel ADC request with DMA on stm32f103c8t6 (bluePill)

sfrwmaker
Associate II

Hello!

Configured 3 input channels to be checked by two ADCs in fast mode. First ADC request works perfectly, but all next request ADC2 data is not synchronized with ADC1. It seems, ADC2 stops incorrectly and continues to change the channels.

Here is an initialization:

#define ADC_CONV   (3)                              // Activated ADC Ranks Number (hadc*.Init.NbrOfConversion)

#define ADC_LOOPS   (1)                              // Number of ADC conversion loops. Should be even

#define ADC_BUFF_SZ   (2*ADC_CONV*ADC_LOOPS)               // Both ADCs are checking input channels

volatile static uint16_t   adc_buff[ADC_BUFF_SZ];

static void MX_ADC1_Init(void)

{

 /* USER CODE BEGIN ADC1_Init 0 */

 /* USER CODE END ADC1_Init 0 */

 ADC_MultiModeTypeDef multimode = {0};

 ADC_ChannelConfTypeDef sConfig = {0};

 /* USER CODE BEGIN ADC1_Init 1 */

 /* USER CODE END ADC1_Init 1 */

 /** Common config

 */

 hadc1.Instance = ADC1;

 hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;

 hadc1.Init.ContinuousConvMode = DISABLE;

 hadc1.Init.DiscontinuousConvMode = DISABLE;

 hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;

 hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;

 hadc1.Init.NbrOfConversion = 3;

 if (HAL_ADC_Init(&hadc1) != HAL_OK)

 {

   Error_Handler();

 }

 /** Configure the ADC multi-mode

 */

 multimode.Mode = ADC_DUALMODE_INTERLFAST;

 if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)

 {

   Error_Handler();

 }

 /** Configure Regular Channel

 */

 sConfig.Channel = ADC_CHANNEL_0;

 sConfig.Rank = ADC_REGULAR_RANK_1;

 sConfig.SamplingTime = ADC_SAMPLETIME_13CYCLES_5;

 if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)

 {

   Error_Handler();

 }

 /** Configure Regular Channel

 */

 sConfig.Channel = ADC_CHANNEL_1;

 sConfig.Rank = ADC_REGULAR_RANK_2;

 if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)

 {

   Error_Handler();

 }

 /** Configure Regular Channel

 */

 sConfig.Channel = ADC_CHANNEL_2;

 sConfig.Rank = ADC_REGULAR_RANK_3;

 if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)

 {

   Error_Handler();

 }

 /* USER CODE BEGIN ADC1_Init 2 */

 /* USER CODE END ADC1_Init 2 */

}

/**

 * @brief ADC2 Initialization Function

 * @param None

 * @retval None

 */

static void MX_ADC2_Init(void)

{

 /* USER CODE BEGIN ADC2_Init 0 */

 /* USER CODE END ADC2_Init 0 */

 ADC_ChannelConfTypeDef sConfig = {0};

 /* USER CODE BEGIN ADC2_Init 1 */

 /* USER CODE END ADC2_Init 1 */

 /** Common config

 */

 hadc2.Instance = ADC2;

 hadc2.Init.ScanConvMode = ADC_SCAN_ENABLE;

 hadc2.Init.ContinuousConvMode = DISABLE;

 hadc2.Init.DiscontinuousConvMode = DISABLE;

 hadc2.Init.ExternalTrigConv = ADC_SOFTWARE_START;

 hadc2.Init.DataAlign = ADC_DATAALIGN_RIGHT;

 hadc2.Init.NbrOfConversion = 3;

 if (HAL_ADC_Init(&hadc2) != HAL_OK)

 {

   Error_Handler();

 }

 /** Configure Regular Channel

 */

 sConfig.Channel = ADC_CHANNEL_0;

 sConfig.Rank = ADC_REGULAR_RANK_1;

 sConfig.SamplingTime = ADC_SAMPLETIME_13CYCLES_5;

 if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK)

 {

   Error_Handler();

 }

 /** Configure Regular Channel

 */

 sConfig.Channel = ADC_CHANNEL_1;

 sConfig.Rank = ADC_REGULAR_RANK_2;

 if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK)

 {

   Error_Handler();

 }

 /** Configure Regular Channel

 */

 sConfig.Channel = ADC_CHANNEL_2;

 sConfig.Rank = ADC_REGULAR_RANK_3;

 if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK)

 {

   Error_Handler();

 }

 /* USER CODE BEGIN ADC2_Init 2 */

 /* USER CODE END ADC2_Init 2 */

}

/**

 * Enable DMA controller clock

 */

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, 0, 0);

 HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);

}

Here is the DMA callback. The highlighted line is a break point:

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) {

   if (hadc->Instance != ADC1) return;

   HAL_ADC_Stop(&hadc2);

   HAL_ADCEx_MultiModeStop_DMA(&hadc1);

   volatile uint8_t ok = 1;

   for (uint8_t l = 0; l < ADC_LOOPS; ++l) {

      for (uint8_t i = 0; i < ADC_CONV; ++i) {

         if (abs(adc_buff[2*i] - adc_buff[2*i+1]) > 5) {

            ok = 0;

            break;

         }

      }

   }

}

Here is a main loop. Here you can see two commented out lines to re-initialize the both ADCs:

 while (1)

 {

   /* USER CODE END WHILE */

   /* USER CODE BEGIN 3 */

      //MX_ADC1_Init();

      //MX_ADC2_Init();

       HAL_ADC_Start(&hadc2);

       HAL_ADCEx_MultiModeStart_DMA(&hadc1, (uint32_t*)adc_buff, ADC_CONV*ADC_LOOPS);

      HAL_Delay(500);

 }

First iteration at the break point shows the following values for adc_buff array:

37,38, 329,329, 646,649

But in the second iteration the values shuffled:

40,645, 327,38, 644,329

In the third iteration:

37,645, 328,39, 645,327

If the two lines MX_ADC1_Init(); & MX_ADC2_Init(); activated, the result become correct:

first iteration:

36,41, 331,329, 652,653

second iteration:

42,39, 338,339, 665,665

Perhaps, it is not good idea to initialize ADCs before each measurement? Does anybody know another way to get correct ADC readings?

3 REPLIES 3
MM..1
Chief

Try dont call

   HAL_ADC_Stop(&hadc2);
 
   HAL_ADCEx_MultiModeStop_DMA(&hadc1);
 

when you dont start continuos , stop isnt necessary.

sfrwmaker
Associate II

Now, both ADC initialized with continous mode disabled:

 hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;

 hadc1.Init.ContinuousConvMode = DISABLE;

 hadc1.Init.DiscontinuousConvMode = DISABLE;

Callback now without stop code.

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) {

   if (hadc->Instance != ADC1) return;

//   HAL_ADC_Stop(&hadc2);

//   HAL_ADCEx_MultiModeStop_DMA(&hadc1);

   volatile uint8_t ok = 1;

   for (uint8_t l = 0; l < ADC_LOOPS; ++l) {

      for (uint8_t i = 0; i < ADC_CONV; ++i) {

         if (abs(adc_buff[2*i] - adc_buff[2*i+1]) > 5) {

            ok = 0;

            break;

         }

      }

   }

}

And start code without ADC_init():

while (1)

 {

   /* USER CODE END WHILE */

   /* USER CODE BEGIN 3 */

//      MX_ADC1_Init();

//      MX_ADC2_Init();

       HAL_ADC_Start(&hadc2);

       HAL_ADCEx_MultiModeStart_DMA(&hadc1, (uint32_t*)adc_buff, ADC_CONV*ADC_LOOPS);

      HAL_Delay(500);

 }

And the result is the same.

First iteration works correctly:

36,37, 313,316, 620,621

Second iteration. Perhaps, ADC2 started with channel 2, 3, and 3.

35,308, 311,613, 615,613

Third iteration:

616,616, 35,306, 305,601. ADC1 - 3,1,2; ADC2 - 3,2,3.

I think the HAL_ADCEx_MultiModeStop_DMA(&hadc1); should be in the callback.

MM..1
Chief

In my F4 adc init have this lines try add to yourboth configs

  hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
  hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV;