cancel
Showing results for 
Search instead for 
Did you mean: 

Software triggered multichannel scan - callback not triggered

NRumm.1
Associate III

Hi, I'm using a STM32F303 with 10 independent analog input channels connected to ADC1 and ADC2 (5 channels per ADC).

What I'd like to achieve is a software triggered scan of all 5+5 channels in one go and have the result copied to memory using DMA. So I went with 'dual regular simultaneous mode' where ADC1 is master and ADC2 is slave.

However, the callback functions HAL_ADC_ConvHalfCpltCallback and HAL_ADC_ConvCpltCallback never get triggered.

I've tried all combinations in ADC settings without any change - except that when using continuous mode the callback functions do get triggered. However that's not what I want - I need only one scan of all channels with the result in memory. Seems I'm lost in the rather confusing ADC settings again.

This is how my board initializes - note that DMA is initialized before ADC1 and ADC2:

 

 

 

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

 

 

 

This is how I setup ADC1:

 

 

 

static void MX_ADC1_Init(void) {
  ADC_MultiModeTypeDef multimode = {0};
  ADC_ChannelConfTypeDef sConfig = {0};

  /** Common config
  */
  hadc1.Instance = ADC1;
  hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
  hadc1.Init.Resolution = ADC_RESOLUTION_10B;
  hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;
  hadc1.Init.ContinuousConvMode = DISABLE;
  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 = 5;
  hadc1.Init.DMAContinuousRequests = DISABLE;
  hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV;
  hadc1.Init.LowPowerAutoWait = DISABLE;
  hadc1.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
  if (HAL_ADC_Init(&hadc1) != HAL_OK)  {
    Error_Handler();
  }

  /** Configure the ADC multi-mode
  */
  multimode.Mode = ADC_DUALMODE_REGSIMULT;
  multimode.DMAAccessMode = ADC_DMAACCESSMODE_12_10_BITS;
  multimode.TwoSamplingDelay = ADC_TWOSAMPLINGDELAY_1CYCLE;
  if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK) {
    Error_Handler();
  }

  /** Configure Regular Channel
  */
  sConfig.Channel = ADC_CHANNEL_1;
  sConfig.Rank = ADC_REGULAR_RANK_1;
  sConfig.SingleDiff = ADC_SINGLE_ENDED;
  sConfig.SamplingTime = ADC_SAMPLETIME_19CYCLES_5;
  sConfig.OffsetNumber = ADC_OFFSET_NONE;
  sConfig.Offset = 0;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)  {
    Error_Handler();
  }

  /** Configure Regular Channel
  */
  sConfig.Rank = ADC_REGULAR_RANK_2;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)  {
    Error_Handler();
  }

  /** Configure Regular Channel
  */
  sConfig.Rank = ADC_REGULAR_RANK_3;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)  {
    Error_Handler();
  }

  /** Configure Regular Channel
  */
  sConfig.Rank = ADC_REGULAR_RANK_4;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)  {
    Error_Handler();
  }

  /** Configure Regular Channel
  */
  sConfig.Rank = ADC_REGULAR_RANK_5;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)  {
    Error_Handler();
  }
}

 

 

 

...and now for ADC2:

 

 

 

static void MX_ADC2_Init(void) {
  ADC_ChannelConfTypeDef sConfig = {0};

  /** Common config
  */
  hadc2.Instance = ADC2;
  hadc2.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
  hadc2.Init.Resolution = ADC_RESOLUTION_10B;
  hadc2.Init.ScanConvMode = ADC_SCAN_ENABLE;
  hadc2.Init.ContinuousConvMode = DISABLE;
  hadc2.Init.DiscontinuousConvMode = DISABLE;
  hadc2.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc2.Init.NbrOfConversion = 5;
  hadc2.Init.DMAContinuousRequests = DISABLE;
  hadc2.Init.EOCSelection = ADC_EOC_SEQ_CONV;
  hadc2.Init.LowPowerAutoWait = DISABLE;
  hadc2.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
  if (HAL_ADC_Init(&hadc2) != HAL_OK)  {
    Error_Handler();
  }

  /** Configure Regular Channel
  */
  sConfig.Channel = ADC_CHANNEL_1;
  sConfig.Rank = ADC_REGULAR_RANK_1;
  sConfig.SingleDiff = ADC_SINGLE_ENDED;
  sConfig.SamplingTime = ADC_SAMPLETIME_19CYCLES_5;
  sConfig.OffsetNumber = ADC_OFFSET_NONE;
  sConfig.Offset = 0;
  if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK)  {
    Error_Handler();
  }

  /** Configure Regular Channel
  */
  sConfig.Rank = ADC_REGULAR_RANK_2;
  if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK)  {
    Error_Handler();
  }

  /** Configure Regular Channel
  */
  sConfig.Rank = ADC_REGULAR_RANK_3;
  if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK)  {
    Error_Handler();
  }

  /** Configure Regular Channel
  */
  sConfig.Rank = ADC_REGULAR_RANK_4;
  if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK)  {
    Error_Handler();
  }

  /** Configure Regular Channel
  */
  sConfig.Rank = ADC_REGULAR_RANK_5;
  if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK)  {
    Error_Handler();
  }
}

 

 

 

Now for the DMA setup:

 

 

 

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

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

 

 

 

Now for the actual launch of an ADC scan:

 

 

 

void Sensor::performMeasurement(uint32_t* buffer, uint32_t size) {
	g_adcConversionComplete = false; // just a global flag

	if (HAL_ADC_Start(&m_adc_handler2) != HAL_OK) {
		return;
	}

	if (HAL_ADCEx_MultiModeStart_DMA(&m_adc_handler1, buffer, size) != HAL_OK) {
		return;
	}

	// wait for the end of the conversion
	while(!g_adcConversionComplete);

	if (HAL_ADC_Stop(&m_adc_handler2) != HAL_OK) {
		return;
	}
	if (HAL_ADCEx_MultiModeStop_DMA(&m_adc_handler1) != HAL_OK) {
		return;
	}
}

 

 

 

...and the callback functions - nothing fancy here:

 

 

 

extern "C" {
	// Called when first half of buffer is filled
	void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef* hadc) {
	  g_adcConversionComplete = false;
	}

	// Called when buffer is completely filled
	void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) {
	  g_adcConversionComplete = true;
	}

	void HAL_ADC_ErrorCallback(ADC_HandleTypeDef *hadc) {
	  Error_Handler();
	}
}

 

 

 

1 REPLY 1
NRumm.1
Associate III

I'm making progress - the reason for never triggering the callback functions was, that the call to ...

HAL_ADCEx_MultiModeStart_DMA(&m_adc_handler1, buffer, size)

...used a twice-as-big number for the size. As such the DMA was waiting for other data to be converted, which explains why it worked in continuous mode but not in simple scan mode.