STM32: Triple Interleaved ADC - Example Code By ST - Page 1
Forum section: electronics / general

author: m.m.m
author_rank: Regular Contributor
timestamp: July 15, 2020, 10:44:45 pm
content: Hello,I just wanted to interleave 3 of my ADCs of my STM32F429ZIT6 and store the data via DMA in a buffer with a length of 3000. The PCLK2 is 45MHz so since each ADC takes 5 cycles to output a result I should be able to get from 4.5 to 1.125 Msps depending on the Prescaler value. I'm using the lowest prescale value at the moment so I should get4.5 Msps.At first, I started to write my own code but I realized thatsome user has an example for this specific application, and I decided to use that. In the example the configuration is as follows:- The buffer is uint32_t- The three ADCs are configured for the same channel obviously- ADC1 is set to:DMAContinuousRequests = ENABLE,ContinuousConvMode = ENABLE- ADC2&3 are set to:DMAContinuousRequests = DISABLE,ContinuousConvMode = ENABLE-mode.Mode = ADC_DUALMODE_INTERL-mode.DMAAccessMode = ADC_DMAACCESSMODE_2So my first problem is that the weird thing about this example is it is configured inDual Interleaved Mode. Is that a mistake? Should it be configured asADC_TRIPLEMODE_INTERLinstead?Then I tried the code and to check whether the code works, I added a HAL_GPIO_TogglePin in bothHAL_ADC_ConvCpltCallback&HAL_ADC_ConvHalfCpltCallback, and I also added a breakpoint in both the toggle lines for debugging. At first when I tried theADC_DUALMODE_INTERLandADC_DMAACCESSMODE_2I got a period of 2 ms on the GPIO pin, which means that I was getting 3000/0.002=1.5Msps If I'm doing the math right. So I think DUALMODE should be changed into TRIPLEMODE, right?So I changed it intoTRIPLEMODEand theDMA Access Modestill set to2and the rest of the configs unchanged, and I got a period of 1.332 ms on the GPIO pin, which corresponds to 3000/0.001332=2.25 Msps which is half of the 4.5 Msps expected rate, Which is again weird.And the next weird thing happened was when I ran the code in debug mode, although I put a breakpoint in the half and full conversion callbacks, the code would stop only when the full length of the buffer is filled.So my second problem is why it doesn't callback at the half-length of the buffer? i.e it breaks at the HAL_ADC_ConvHalfCpltCallback but when it does the buffer is already filled up.That might also be the reason why I was reading half the expected sample rate. The buffer is actually filled at the twice speed I was reading.And my third problem is that inADC_DMAACCESSMODE_2according to the datasheet we have:1st request: ADC_CDR[31:0] = ADC2_DR[15:0] | ADC1_DR[15:0]2nd request: ADC_CDR[31:0] = ADC1_DR[15:0] | ADC3_DR[15:0]3rd request: ADC_CDR[31:0] = ADC3_DR[15:0] | ADC2_DR[15:0]4th request: ADC_CDR[31:0] = ADC2_DR[15:0] | ADC1_DR[15:0], ...So in order to process the data stored in the buffer, later I would need to convert this 32-bit array into a 16-bit buffer of double the length, which would take some time and need some processing power. So now I thought if I could use theADC_DMAACCESSMODE_1then I should be able to get the data in the required 16-bit format which would take double DMA requests but would, in turn, reduce the processing time. So I changed theDMA access modeto1, and did the same GPIO period measurement. The period is 500us which would give us 3000/0.0005 = 6 Msps! So what just happened here? How can I properly set it up in the Access Mode 1?Thanks in advance

author: george4657
author_rank: Contributor
timestamp: July 16, 2020, 02:43:59 am
content: I ran my nucleo 429 board in triple weave. I ran a 72mhz clock divided by 2 by the adc to 36 mhz. In triple mode 10 bits this gave me 7.2 Mps.I used cubeMX and set up ADC1 in triple mode and system setup adc2 and 3 to match.(see attached)DMA attached to adc1 only ,circular mode ,data width word.Buffer has to be setup as a 32bit buffer. First 2 conversions (16 + 16 bits) go in buffer third and fourth go in buffer and fifth and sixth go into buffer then series repeats. Your buffer should be diviseble by 3DMA does not stop when you break to debug so second half of buffer keeps on filling while you are stopped and it is so fast that it looks like it was pre filled.I used software start so I my code://initializeMX_DMA_Init();MX_ADC1_Init();MX_ADC2_Init();MX_ADC3_Init();// then startHAL_ADC_Start(&hadc3);HAL_ADC_Start(&hadc2);HAL_ADCEx_MultiModeStart_DMA(&hadc1,(uint32_t*) adcBuffer,SizeADCTriple) ;Hope this helps, it took a lot of trial and error to do this.George

author: m.m.m
author_rank: Regular Contributor
timestamp: July 16, 2020, 11:42:43 am
content: Quote from: george4657 on July 16, 2020, 02:43:59 amThank you George.Iscontinuous conversionenabled for ADC2&3?Did you have an approach to measure the sample rate? What was your approach?

author: george4657
author_rank: Contributor
timestamp: July 16, 2020, 03:40:26 pm
content: continuous conversion is enabled for ADC2&3DMA continuous requests is disabled for ADC2&3I also setup DAC to generate waveform for test.I then viewed the result on my 100 mhz oscilloscope and compared to result for stm32 and they showed the same shape and frequency.I sent the data to a windows visual studio program to view data so I could also verify data collected

author: mem2mem
author_rank: Newbie
timestamp: July 27, 2020, 01:41:25 pm
content: Quote from: george4657 on July 16, 2020, 02:43:59 amHi，I'm trying to use triple interleaved adc in my stm32f429 discovery board, and configured cubemx just the way you did. I use this function (HAL_ADCEx_MultiModeStart_DMA(&hadc1,(uint32_t*) ADCBuff,3) ） to get result to the ADCBuff. By using debugger, I found that the result in the ADCBuff are correct, but it never execute a single line in the while(1) loop in the main function, it really confuses me. How can I set this correctly?here are part of my code.MX_DMA_Init();MX_ADC1_Init();MX_ADC2_Init();MX_ADC3_Init();/* USER CODE BEGIN 2 */HAL_ADC_Start(&hadc3);HAL_ADC_Start(&hadc2);HAL_ADCEx_MultiModeStart_DMA(&hadc1,(uint32_t *)ADCBuff, 3);/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */ADCVaule = ADCBuff & 0xFFFF;ADCVaule = (ADCBuff>>16) & 0xFFFF;ADCVaule = ADCBuff & 0xFFFF;ADCVaule = (ADCBuff>>16) & 0xFFFF;ADCVaule = ADCBuff & 0xFFFF;ADCVaule = (ADCBuff>>16) & 0xFFFF;}/* USER CODE END 3 */

author: aheid
author_rank: Regular Contributor
timestamp: July 29, 2020, 05:14:51 am
content: Your while loop code doesn't seem do anything so maybe the compiler optimized it out?ADCBuff should be marked volatile, in case you haven't. Might even make the compiler see past the futility of the loop.