2021-06-21 10:31 AM
Greetings,
I'm using an STM32F476, and I have configured ADC1 to read from 9 different inputs.
My goal is achieve 200Hz, which should be very achievable considering the speed of the ADC on these MCUs.
The issue I am experiencing is that it seems the ADC readings are "interrupted" about every 1.5 seconds or so.
What I've done to configure this (code below) is configured the ADC to use DMA, and TIM3 at 200Hz. When the TIM3 interrupt occurs I call HAL_ADC_Start_DMA() and store this in memory for 5 seconds. Once the reading is completed, I write it to the serial port.
ADC config:
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV256;
hadc1.Init.Resolution = ADC_RESOLUTION_12B;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;
hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
hadc1.Init.LowPowerAutoWait = DISABLE;
hadc1.Init.ContinuousConvMode = ENABLE;
hadc1.Init.NbrOfConversion = 9;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc1.Init.DMAContinuousRequests = ENABLE;
hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED;
hadc1.Init.OversamplingMode = DISABLE;
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_1;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_2CYCLES_5;
sConfig.SingleDiff = ADC_SINGLE_ENDED;
sConfig.OffsetNumber = ADC_OFFSET_NONE;
sConfig.Offset = 0;
htim3.Instance = TIM3;
htim3.Init.Prescaler = 11;
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
htim3.Init.Period = 33332;
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
// start the ADC->DMA conversion
get_adc_dma();
}
void get_adc_dma(void){
if (collect) {
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_buffer, ADC_CHANNELS);
memcpy(adc_pool[counter], adc_buffer, sizeof(adc_buffer));
counter++;
if (counter >= 1000) {
collect = false;
send_data();
}
}
}
The output I am seeing Is not good.
I was streaming this directly to the serial port, and I considered that was an issue with timing. After removing that stream, and storing it directly in memory I was confident that it was not the serial port.
I'm sure I could have included more code, but I included what I felt was pertinent.
Thanks for any ideas/help on why this is happening.
2021-06-21 10:59 AM
Does send_data block for a significant amount of time? If TIM3 interrupts at 200Hz, you have 5ms to send out all the data without causing interruptions.
A better way would be to use a larger buffer, capture ADC data in DMA CIRCULAR mode, and use the half- and full- transfer complete interrupts to process each half of of the buffer as they are populated.
2021-06-21 11:52 AM
send_data() happens after the data collection is done (1000 records over 5 seconds)
I use the counter to count up to 1000, and then once 1000 is hit the data it sent. Hope that makes sense.