cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F446 multiple samples of a single channel with timer-driven ADC DMA

Matt Blessinger
Associate III

I want to setup an ADC in DMA triggered by a 1Hz timer to sample a single channel n-number times consecutively. Currently I can do that with this code (relevant parts only) but only if the number of samples is 16 or fewer, but I want to do more (50-100). The 16 limit comes from the maximum number of ranks for scan conversion mode.

void MX_ADC3_Init(void) {
…
  hadc3.Init.ScanConvMode = ENABLE;
  hadc3.Init.ContinuousConvMode = DISABLE;
  hadc3.Init.DiscontinuousConvMode = DISABLE;
  hadc3.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING;
  hadc3.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T2_TRGO;
  hadc3.Init.NbrOfConversion = 10;
  hadc3.Init.DMAContinuousRequests = ENABLE;
…
  sConfig.Channel = ADC_CHANNEL_2;
  sConfig.Rank = 1;
  sConfig.SamplingTime = ADC_SAMPLETIME_480CYCLES;
  if (HAL_ADC_ConfigChannel(&hadc3, &sConfig) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }
…
  sConfig.Rank = 10;
  if (HAL_ADC_ConfigChannel(&hadc3, &sConfig) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }
}

DMA is in circular mode, and I start the ADC with this code.

HAL_TIM_Base_Start_IT(&htim2);
HAL_ADC_Start_DMA(&hadc3, (uint32_t*)rawValues3, numADC3);

Where rawValues3 is a uint16_t array of size 10 and numADC3 is 10. This works fine; the timer updates at 1Hz and it samples the single ADC channel 10 times.

So the question is how to do the same thing but with >16 samples. After trying many different combinations the only thing I got working is the following code. In essence I no longer start the ADC with the timer trigger and instead start the ADC in the timer IRQ handler every update. I also change the ADC to a continuous conversion mode so that it fills the buffer to whatever size I set.

void MX_ADC3_Init(void) {
…
  hadc3.Init.ScanConvMode = DISABLE;
  hadc3.Init.ContinuousConvMode = ENABLE;
  hadc3.Init.DiscontinuousConvMode = DISABLE;
  hadc3.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
  hadc3.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc3.Init.NbrOfConversion = 1;
  hadc3.Init.DMAContinuousRequests = ENABLE;
…
  sConfig.Channel = ADC_CHANNEL_2;
  sConfig.Rank = 1;
  sConfig.SamplingTime = ADC_SAMPLETIME_480CYCLES;
  if (HAL_ADC_ConfigChannel(&hadc3, &sConfig) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }
}

DMA is in normal mode, and I start the timer with HAL_ADC_START_DMA inside the timer IRQ handler. If DMA is in circular mode it continuously fills the buffer instead of at the timer frequency.

So I can sample the same ADC channel as many times as I want at a given frequency, but I have to call HAL_ADC_START_DMA in the IRQ handler every time. I’d rather have that function in the background based on the timer update trigger. In the case that I need to precisely time the start of ADC conversion, HAL_ADC_START_DMA takes a non negligible amount of time to complete. Does anybody know how to do that?

Sorry if this came out as a ramble. Let me know if I need to include any more information. Thank you!

2 REPLIES 2
suraj.pai
Associate

Any update on this?

I have a similar situation.

I have to read a adc differential ended signal at 9600 hz. I have setup adc trigger based on timer but I need to read 1024 samples before processing. I have also setup DMA. Something doesn't seem right when I plot adc values.

DMA continuous enabled

Timer Update event trigger

No Scan Mode

Continuous Conversion.

No of conversion= 1

DMA circular Mode

Hal_ADC_StartDMA(&hadc1,adcBuffer,1024);

 

Is this correct???

Unfortunately the F4 family is already being put aside, it was launched in 2011. But you may be able to find posts on the internet that help, try these keywords:

https://www.google.com/search?q=stm32+adc+multi+channel+example