Author Topic: STM32: Triple Interleaved ADC - Example Code By ST  (Read 2418 times)

0 Members and 1 Guest are viewing this topic.

Offline m.m.mTopic starter

  • Regular Contributor
  • *
  • Posts: 105
  • Country: ir
  • EE MSc Student and Hobbyist
STM32: Triple Interleaved ADC - Example Code By ST
« on: July 15, 2020, 10:44:45 pm »
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 get 4.5 Msps.

At first, I started to write my own code but I realized that some 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_2

  • So my first problem is that the weird thing about this example is it is configured in Dual Interleaved Mode. Is that a mistake? Should it be configured as ADC_TRIPLEMODE_INTERL instead?

Then I tried the code and to check whether the code works, I added a HAL_GPIO_TogglePin in both HAL_ADC_ConvCpltCallback & HAL_ADC_ConvHalfCpltCallback , and I also added a breakpoint in both the toggle lines for debugging. At first when I tried the ADC_DUALMODE_INTERL and ADC_DMAACCESSMODE_2 I 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 into TRIPLEMODE and the DMA Access Mode still set to 2 and 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 in ADC_DMAACCESSMODE_2 according 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 the ADC_DMAACCESSMODE_1 then 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 the DMA access mode to 1, 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
« Last Edit: July 16, 2020, 03:51:56 pm by m.m.m »
25 y/o Electronics Lover
 

Offline george4657

  • Contributor
  • Posts: 10
  • Country: ca
Re: STM32: Triple Interleaved - Example Code By ST
« Reply #1 on: July 16, 2020, 02:43:59 am »
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[0] third and fourth go in buffer[1] and fifth and sixth go into buffer[3] then series repeats. Your buffer should be diviseble by 3

DMA 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:
//initialize   
  MX_DMA_Init();
  MX_ADC1_Init();
  MX_ADC2_Init();
  MX_ADC3_Init();

// then start

HAL_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

 
 
The following users thanked this post: m.m.m, mem2mem

Offline m.m.mTopic starter

  • Regular Contributor
  • *
  • Posts: 105
  • Country: ir
  • EE MSc Student and Hobbyist
Re: STM32: Triple Interleaved - Example Code By ST
« Reply #2 on: July 16, 2020, 11:42:43 am »
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[0] third and fourth go in buffer[1] and fifth and sixth go into buffer[3] then series repeats. Your buffer should be diviseble by 3

DMA 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:
//initialize   
  MX_DMA_Init();
  MX_ADC1_Init();
  MX_ADC2_Init();
  MX_ADC3_Init();

// then start

HAL_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

Thank you George.
Is continuous conversion enabled for ADC2&3?
Did you have an approach to measure the sample rate? What was your approach?
25 y/o Electronics Lover
 

Offline george4657

  • Contributor
  • Posts: 10
  • Country: ca
Re: STM32: Triple Interleaved - Example Code By ST
« Reply #3 on: July 16, 2020, 03:40:26 pm »
 continuous conversion is enabled for ADC2&3
DMA continuous requests is disabled for ADC2&3

I 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
 
The following users thanked this post: m.m.m

Offline mem2mem

  • Newbie
  • Posts: 7
  • Country: cn
Re: STM32: Triple Interleaved - Example Code By ST
« Reply #4 on: July 27, 2020, 01:41:25 pm »
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[0] third and fourth go in buffer[1] and fifth and sixth go into buffer[3] then series repeats. Your buffer should be diviseble by 3

DMA 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:
//initialize   
  MX_DMA_Init();
  MX_ADC1_Init();
  MX_ADC2_Init();
  MX_ADC3_Init();

// then start

HAL_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




Hi,

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[0] = ADCBuff[0] & 0xFFFF;
      ADCVaule[1] = (ADCBuff[0]>>16) & 0xFFFF;
      ADCVaule[2] = ADCBuff[1] & 0xFFFF;
      ADCVaule[3] = (ADCBuff[1]>>16) & 0xFFFF;
      ADCVaule[4] = ADCBuff[2] & 0xFFFF;
      ADCVaule[5] = (ADCBuff[2]>>16) & 0xFFFF;
  }
  /* USER CODE END 3 */
 

Offline aheid

  • Regular Contributor
  • *
  • Posts: 245
  • Country: no
Re: STM32: Triple Interleaved ADC - Example Code By ST
« Reply #5 on: July 29, 2020, 05:14:51 am »
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.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf