Averaging Multichannel ADC data on STM32F4 - Page 1
Forum section: electronics / general

author: ZeroResistance
author_rank: Frequent Contributor
timestamp: October 02, 2017, 08:15:53 am
content: I am reading 4 adc channels of the STM32F407VG on a STM32F4 Discovery Board.Currently with CubeMX I've got the 4 adc channels initialized and the ADC is scanning and converting these 4 channels continuously and using DMA to transfer the result to a buffer in memory.However the buffer is only 4 elements and each channel is stored seperately in each element of the buffer.But this is not what I want, I would like to perform averaging on the ADC values, typically I would like to store the ADC values coming from each channel in a 16 element or 32 element buffer and perform a rolling average on them.Is there a way to do this with DMA and with least CPU intervention?TIA

author: mikerj
author_rank: Super Contributor
timestamp: October 02, 2017, 09:56:18 am
content: There is no way to perform the averaging autonomously, it has to be done in software. You simply make the DMA buffer as large as it needs to be (i.e. channels * samples * 2 bytes) and then perform the averaging when the DMA transfer has completed. The samples will be stored in channel scan order e.g. if scanning channels 1-4:Chan 1Chan 2Chan 3Chan 4Chan 1Chan 2Chan 3Chan 4etc.The averaging could look something like this:Code:uint16_t i = ADC_SAMPLES;uint16_t *dma = dmabuffer;uint32_t chan1 = 0;uint32_t chan2 = 0;uint32_t chan3 = 0;uint32_t chan4 = 0;do {chan1 += *dma++;chan2 += *dma++;chan3 += *dma++;chan4 += *dma++;} while (--i > 0 );chan1 /= ADC_SAMPLES;chan2 /= ADC_SAMPLES;chan3 /= ADC_SAMPLES;chan4 /= ADC_SAMPLES;If speed is critical you could save some cycles by unrolling the loop, either partially or fully if the number of samples is reasonably low.

author: xani
author_rank: Frequent Contributor
timestamp: October 02, 2017, 10:06:52 am
content: For longer rolling averages it would probably make sense to use function like EWMA which doesn't grow with length of data.Quote from: mikerj on October 02, 2017, 09:56:18 amWell, there is, via RC filter. But realistically it would be nice to at least have an opamp before it.

author: ZeroResistance
author_rank: Frequent Contributor
timestamp: October 02, 2017, 10:24:12 am
content: Thanks for the info mikerjWhat you are trying to say is instead of using Circular DMA use Normal DMA and also increase the size of the DMA buffer.So I get something like what you showedChan1, Chan2, Chan3, Chan4, Chan1, Chan2 .... and so onNow suppose I need 16 sets of readings for Chan1 to Chan4 and 2 bytes each per channel. so that would make a 16 * 4 * 2 = 128 byte buffer.So if the the 128byte buffer overflows do I have to set the DMA manually back to the start of the buffer?Also you are doing this averaging after the needed 16 samples per channel are acquired right?

author: ZeroResistance
author_rank: Frequent Contributor
timestamp: October 02, 2017, 10:27:25 am
content: Many thanks for the suggestion on EWMA.

author: mikerj
author_rank: Super Contributor
timestamp: October 02, 2017, 12:02:05 pm
content: Quote from: ZeroResistance on October 02, 2017, 10:24:12 amYes, this is how I have implemented this on an STM32F103.Quote from: ZeroResistance on October 02, 2017, 10:24:12 amYou will need to re-start the DMA after the transfer has completed. How and when you do this depend on how often you want a new filtered ADC value. For maximum throughput you could use the end of transfer interrupt to start a new DMA transfer in a second buffer whilst averaging the values in the first (i.e. double buffering).Quote from: ZeroResistance on October 02, 2017, 10:24:12 amYes, you acquire the samples and then average them.In the system I was working on we used oversampling to gain some more resolution. The DMA was started by a timer interrupt and the averaging was performed in the end of transfer interrupt. IIRC there was 5 or 6 ADC channels, 64 samples from each channel and the calculations were quite fast, less than 50 microseconds with full C optimisations enabled. Our clock speed was fairly low as well, only about 33MHz.

author: ZeroResistance
author_rank: Frequent Contributor
timestamp: October 02, 2017, 02:54:54 pm
content: Many thanks for your inputs, mikerj. It certainly helps to know that the chip cannot do this on itsown and certain amount of CPU intervention would be required.On another note I have connected 10K ohm pots to each of the ADC inputs and I see a certain amount of crosstalk between adjacent channels. That is if I increase the value of one channel by turning the pot I can see a slight increase in value of the next channel.The ADC clock is set to 21MhzCurrently my conversion time is 15 ADC clock cycles and sampling time is 3cycles.

author: MT
author_rank: Super Contributor
timestamp: October 02, 2017, 08:58:58 pm
content: Quote from: ZeroResistance on October 02, 2017, 02:54:54 pmF4 ADC is famous for its internal noise and other ""things"", there are a noise reduction sugestion paper available from ST. If you are planning to ""try"" to get low noise results you ""must"" read this paper. You cant assume to get godADC results from Nucleo borads/Discovery boards, they where not designed with that in mind, particularely not the 64pin Nucleo/Aurdiono compatible crap boards.

author: pigrew
author_rank: Frequent Contributor
timestamp: October 03, 2017, 03:10:52 pm
content: Based on the STM app note AN2834 (How to get the best ADC accuracy in STM32 microcontrollers), their STM32L0 and STM32L4 MCUs support hardware oversampling, so that would be the least software-involvement method, but involve a change in MCU.With the 'F4, you have to do software averaging after transferring the individual samples with DMA.

author: Jeroen3
author_rank: Super Contributor
timestamp: October 04, 2017, 07:08:19 am
content: Just left align the halfword, run the EWMA en you have aq16to work with.