2018-11-07 05:15 PM
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!
2023-07-30 02:21 AM
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???
2023-07-30 10:28 PM
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