cancel
Showing results for 
Search instead for 
Did you mean: 

Stm32 H7 ADC Conversion time ?

A.Caliskan
Associate II

Hello 

I m trying measure adc conversion time , I look datasheet , f_adc=37 Mhz(for fast channel) 

with 12 bit resulation, 4.10 MSps , so ı use f_adc=32 Mhz(for fast channel) with 12 bit resulation, 3.54 MSps should be, but I m not measure 3.54 MSps,I measure 892 Ksps My measurement is as follows, when entering dma interrupt ,I toggle pin , then I set another pin At the end of the interrupt, I reset the pin again. the difference between the two times gives the adc conversion time.where is my fault project file and oscilloscope images are attached.

#include "main.h"
 
 
uint32_t cosa;
 
void SystemClock_Config(void);
void PeriphCommonClock_Config(void);
static void MX_GPIO_Init(void);
 
void adc2_config()
{
 
 
	          LL_ADC_InitTypeDef ADC_InitStruct = {0};
			  LL_ADC_REG_InitTypeDef ADC_REG_InitStruct = {0};
			  LL_ADC_CommonInitTypeDef ADC_CommonInitStruct = {0};
 
			  LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
			  LL_RCC_SetADCClockSource(LL_RCC_ADC_CLKSOURCE_CLKP);
			  LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_ADC12);
			  LL_AHB4_GRP1_EnableClock(LL_AHB4_GRP1_PERIPH_GPIOB);
 
			  GPIO_InitStruct.Pin = LL_GPIO_PIN_1;
			  GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG;
			  GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
			  LL_GPIO_Init(GPIOB, &GPIO_InitStruct);
 
 
 
			  ADC_InitStruct.Resolution = LL_ADC_RESOLUTION_12B;
			  ADC_InitStruct.LowPowerMode = LL_ADC_LP_MODE_NONE;
			  LL_ADC_Init(ADC2, &ADC_InitStruct);
			  ADC_REG_InitStruct.TriggerSource = LL_ADC_REG_TRIG_SOFTWARE;
			  ADC_REG_InitStruct.SequencerLength = LL_ADC_REG_SEQ_SCAN_DISABLE   ;
			  ADC_REG_InitStruct.SequencerDiscont = LL_ADC_REG_SEQ_DISCONT_DISABLE ;
			  ADC_REG_InitStruct.ContinuousMode = LL_ADC_REG_CONV_SINGLE ;
			  ADC_REG_InitStruct.Overrun = LL_ADC_REG_OVR_DATA_OVERWRITTEN;
			  ADC_REG_InitStruct.DataTransferMode=LL_ADC_REG_DMA_TRANSFER_UNLIMITED;
			  LL_ADC_REG_Init(ADC2, &ADC_REG_InitStruct);
			  LL_ADC_SetOverSamplingScope(ADC2, LL_ADC_OVS_DISABLE);
			 // LL_ADC_REG_SetTriggerEdge(ADC2, LL_ADC_REG_TRIG_EXT_RISING);
			  ADC_CommonInitStruct.CommonClock =LL_ADC_CLOCK_ASYNC_DIV2;
			  ADC_CommonInitStruct.Multimode = LL_ADC_MULTI_INDEPENDENT;
			  LL_ADC_CommonInit(__LL_ADC_COMMON_INSTANCE(ADC2), &ADC_CommonInitStruct);
 
			  LL_ADC_DisableDeepPowerDown(ADC2);
 
			  LL_ADC_EnableInternalRegulator(ADC2);
 
			 	  uint32_t wait_loop_index;
			 	  wait_loop_index = ((LL_ADC_DELAY_INTERNAL_REGUL_STAB_US * (SystemCoreClock / (100000 * 2))) / 10);
			 	  while(wait_loop_index != 0)
			 	  {
			 	    wait_loop_index--;
			 	  }
 
			 	   LL_ADC_StartCalibration(ADC2,LL_ADC_CALIB_OFFSET , LL_ADC_SINGLE_ENDED);
			 	   while (LL_ADC_IsCalibrationOnGoing(ADC2) != 0);
 
			  LL_ADC_SetBoostMode(ADC2,LL_ADC_BOOST_MODE_50MHZ);
 
			 	 LL_ADC_REG_SetSequencerRanks(ADC2, LL_ADC_REG_RANK_1, LL_ADC_CHANNEL_5);
			 	LL_ADC_SetChannelSamplingTime(ADC2, LL_ADC_CHANNEL_5,LL_ADC_SAMPLINGTIME_2CYCLES_5 );
			 	 LL_ADC_SetChannelSingleDiff(ADC2, LL_ADC_CHANNEL_5, LL_ADC_SINGLE_ENDED);
 
			 	LL_ADC_SetChannelPreSelection(ADC2, LL_ADC_CHANNEL_5);//PB1
 
			 		  LL_ADC_Enable(ADC2);
 
 
 
}
void adc2_dma_config()
{
 
	  LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA2);
				 LL_DMA_InitTypeDef DMA_InitStruct = {0};
 
				 NVIC_SetPriority(DMA2_Stream1_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0));
				 NVIC_EnableIRQ(DMA2_Stream1_IRQn);
 
 
 
 
			     DMA_InitStruct.Direction=LL_DMA_DIRECTION_PERIPH_TO_MEMORY;
				 DMA_InitStruct.FIFOMode=LL_DMA_FIFOMODE_DISABLE;
				 DMA_InitStruct.FIFOThreshold=LL_DMA_FIFOTHRESHOLD_FULL;
				 DMA_InitStruct.MemBurst=LL_DMA_MBURST_SINGLE;
				 DMA_InitStruct.MemoryOrM2MDstAddress= (uint32_t)&cosa;
				 DMA_InitStruct.MemoryOrM2MDstDataSize=LL_DMA_MDATAALIGN_WORD;
				 DMA_InitStruct.MemoryOrM2MDstIncMode=LL_DMA_MEMORY_INCREMENT;
				 DMA_InitStruct.Mode=LL_DMA_MODE_CIRCULAR   ;
				 DMA_InitStruct.NbData=1;
				 DMA_InitStruct.PeriphBurst=LL_DMA_PBURST_SINGLE;
				 DMA_InitStruct.PeriphOrM2MSrcAddress=(uint32_t)&ADC2->DR;
				 DMA_InitStruct.PeriphOrM2MSrcDataSize=LL_DMA_PDATAALIGN_WORD ;
				 DMA_InitStruct.PeriphOrM2MSrcIncMode=LL_DMA_PERIPH_NOINCREMENT;
				 DMA_InitStruct.Priority=LL_DMA_PRIORITY_VERYHIGH ;
				 DMA_InitStruct.PeriphRequest= LL_DMAMUX1_REQ_ADC2;
				 LL_DMA_Init(DMA2,  LL_DMA_STREAM_1, & DMA_InitStruct);
 
 
				 LL_DMA_EnableStream(DMA2, LL_DMA_STREAM_1);
				 LL_DMA_EnableIT_TC(DMA2, LL_DMA_STREAM_1);
				 LL_DMA_EnableIT_TE(DMA2, LL_DMA_STREAM_1);
 
}
 
 
 
 void DMA2_Stream1_IRQHandler(void)
 {
	 LL_GPIO_TogglePin(GPIOB, LL_GPIO_PIN_0);// oscilloscope CH3
      GPIOA->BSRR=0x00000001;//// oscilloscope CH4
 	  if(LL_DMA_IsActiveFlag_TC1(DMA2))
 	 {
 
 
 		 LL_DMA_ClearFlag_TC1(DMA2);
 		 LL_ADC_REG_StartConversion(ADC2);
 
 		GPIOA->BSRR=0x00010000;//// oscilloscope CH4
 
 	 }
 
 }
 
 
 
 
 
int main(void)
{
 
 
  LL_APB4_GRP1_EnableClock(LL_APB4_GRP1_PERIPH_SYSCFG);
 
  NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);
 
 
  NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),15, 0));
 
 
 
  SystemClock_Config();
 
 
 
  /
  MX_GPIO_Init();
  
 
  adc2_dma_config();
  adc2_config();
 
 
 while (LL_ADC_IsActiveFlag_ADRDY(ADC2) == 0)
         {
 
        }
    LL_ADC_REG_StartConversion(ADC2);
 
 
  while (1)
  {
  
  }
 
}
 
 
void SystemClock_Config(void)
{
  LL_FLASH_SetLatency(LL_FLASH_LATENCY_3);
  while(LL_FLASH_GetLatency()!= LL_FLASH_LATENCY_3)
  {
  }
  LL_PWR_ConfigSupply(LL_PWR_LDO_SUPPLY);
  LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE0);
  LL_RCC_HSI_Enable();
 
   /* Wait till HSI is ready */
  while(LL_RCC_HSI_IsReady() != 1)
  {
 
  }
  LL_RCC_HSI_SetCalibTrimming(32);
  LL_RCC_HSI_SetDivider(LL_RCC_HSI_DIV1);
  LL_RCC_PLL_SetSource(LL_RCC_PLLSOURCE_HSI);
  LL_RCC_PLL1P_Enable();
  LL_RCC_PLL1_SetVCOInputRange(LL_RCC_PLLINPUTRANGE_8_16);
  LL_RCC_PLL1_SetVCOOutputRange(LL_RCC_PLLVCORANGE_WIDE);
  LL_RCC_PLL1_SetM(4);
  LL_RCC_PLL1_SetN(30);
  LL_RCC_PLL1_SetP(1);
  LL_RCC_PLL1_SetQ(2);
  LL_RCC_PLL1_SetR(2);
  LL_RCC_PLL1_Enable();
 
   /* Wait till PLL is ready */
  while(LL_RCC_PLL1_IsReady() != 1)
  {
  }
 
   /* Intermediate AHB prescaler 2 when target frequency clock is higher than 80 MHz */
   LL_RCC_SetAHBPrescaler(LL_RCC_AHB_DIV_2);
 
  LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL1);
  LL_RCC_SetSysPrescaler(LL_RCC_SYSCLK_DIV_1);
  LL_RCC_SetAHBPrescaler(LL_RCC_AHB_DIV_2);
  LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_2);
  LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_2);
  LL_RCC_SetAPB3Prescaler(LL_RCC_APB3_DIV_2);
  LL_RCC_SetAPB4Prescaler(LL_RCC_APB4_DIV_2);
 
  LL_Init1msTick(480000000);
 
  LL_SetSystemCoreClock(480000000);
}
 
 
void PeriphCommonClock_Config(void)
{
  LL_RCC_SetCLKPClockSource(LL_RCC_CLKP_CLKSOURCE_HSI);
}
 
 
static void MX_GPIO_Init(void)
{
  LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
 
  /* GPIO Ports Clock Enable */
 
  LL_AHB4_GRP1_EnableClock(LL_AHB4_GRP1_PERIPH_GPIOA);
  LL_AHB4_GRP1_EnableClock(LL_AHB4_GRP1_PERIPH_GPIOB);
 
  /**/
  LL_GPIO_ResetOutputPin(GPIOA, LL_GPIO_PIN_0);
 
  /**/
  LL_GPIO_ResetOutputPin(GPIOB, LL_GPIO_PIN_0);
 
  /**/
  GPIO_InitStruct.Pin = LL_GPIO_PIN_0;
  GPIO_InitStruct.Mode = LL_GPIO_MODE_OUTPUT;
  GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
  GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
  GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
  LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
 
  /**/
  GPIO_InitStruct.Pin = LL_GPIO_PIN_0;
  GPIO_InitStruct.Mode = LL_GPIO_MODE_OUTPUT;
  GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
  GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
  GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
  LL_GPIO_Init(GPIOB, &GPIO_InitStruct);
 
}
 

0693W00000GZb31QAD.jpg0693W00000GZb2wQAD.png0693W00000GZb2rQAD.png 

9 REPLIES 9
A.Caliskan
Associate II

I m use stm32h723zg

Please don't PM me about threads.

You can't interrupt at the MHz rates, so instead of doing ONE sample, sample 10 or 100 and decimate the time to understand the sample rate. Use ping-pong buffers with the DMA HT/TC so you aren't working on active/changing data. Watch/manage cache coherency.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
TDK
Guru

You cannot effectively measure the time for a single conversion. As I said in the other post you found, time 10000 conversions to reduce the overhead.

If you feel a post has answered your question, please click "Accept as Solution".

in other post, The person asking the question could not find a solution. so ı open new post because ı have same problem. I did what you said but the result did not change. time is still too long.

Can you explain this part-> "Use ping-pong buffers with the DMA HT/TC so you aren't working on active/changing data. Watch/manage cache coherency."

WQ
Associate III

TDK, can you elaborate on "You cannot effectively measure the time for a single conversion"? Thanks.

-WQ

Tesla, can you elaborate on "You can't interrupt at the MHz rates?

-WQ

Hard to prove a negative. The overhead on cpu timer/monitoring is on the same order as the conversion time. You cannot separate the signal from the noise/overhead on a single conversion. For many conversions, the overhead is comparatively much less of a proportion.
If you feel a post has answered your question, please click "Accept as Solution".

Well you'll saturate the MCU with a lot of context switching and all the burden you're carrying with the handlers, the HAL, and the callbacks.

The ceiling here is probably a lot lower than you think it is, and it scales very badly.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..