cancel
Showing results for 
Search instead for 
Did you mean: 

STM32H7ZI2 NUCLEO - ADC DMA Multi channels are so slow - 10us at 75Mhz ADC_CLK || 400MHz Main Clock

DPham.2
Associate II

Sorry for my bad English. I am using NUCLEO STM32H743ZI2 with ADC multi-channel. I am using 3ADC: ADC 1, 2, and 3 independent mode triggered by TIM1CH1

The CPU clock is 400MHz using an external HSE

STM32H7-> The TIM PWM works well, and it can trigger the ADC measurement. ADC can read the value properly, However, the ADC sampling and conversion took a lot of time than expected with around 10us !!! - too long a time. (I selected 1.5cycle)

Compared to TI TMS320F 28379D - with around 1us, the STM32H7 is much slower :(

COULD YOU PLEASE TELL ME WHAT IS MY ISSUE related to the ADC sampling and converting time ??? . I have tried to read many threads on the internet but no hope, disable ADC2 and ADC3 do not improve the performance :(

I have attached the project so you can import the project and see the delay.

TIM1CH1 (the one trigger ADC) : PE9

GPIO used to check the computation time PG12

https://1drv.ms/u/s!AuUAN7PWAxFS8l3wJ1uhJ_1y7zx8?e=jOM8Gd

0693W00000BdVJLQA3.png0693W00000BdVKOQA3.png0693W00000BdVKEQA3.jpg0693W00000BdVJuQAN.jpg0693W00000BdVJfQAN.png0693W00000BdVJQQA3.png========================CODE =================

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) //

{

 if(hadc->Instance == ADC1)

 {

if(SW_CASE1==50 )

{TIM1->CCR1 = 0; SW_CASE1=0; } // TESTING

  /* Invalidate Data Cache to get the updated content of the SRAM on the second half of the ADC converted data buffer: 32 bytes */

 if (__HAL_ADC_GET_FLAG(hadc, ADC_FLAG_EOS))

 {

 HAL_GPIO_WritePin(GPIOG, GPIO_PIN_12,1); // //GPIO TEST COMPUTATION BURDEN

for (int i =0; i<4; i++) // 4_ADC-> 0,1,2,3

{

adc1_value[i] = ADC_DATA[i];

}

for (int i =0; i<4; i++) // 4_ADC-> 0,1,2,3

{

adc2_value[i] = ADC_DATA_2[i];

}

for (int i =0; i<4; i++) // 4_ADC-> 0,1,2,3

{

adc3_value[i] = ADC_DATA_3[i];

}

HAL_GPIO_WritePin(GPIOG, GPIO_PIN_12,0); // //GPIO TEST COMPUTATION BURDEN

 HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8,0); // //GPIO TEST COMPUTATION BURDEN

  } // END __HAL_ADC_GET_FLAG

 }//END hadc->Instance

} // END HAL_ADC_ConvCpltCallback

void HAL_TIM_PeriodElapsedCallback ( TIM_HandleTypeDef * htim)

{

HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8,1); // //GPIO TEST COMPUTATION BURDEN

}

int main(void)

{

 /* USER CODE BEGIN 1 */

 /* USER CODE END 1 */

 /* MCU Configuration--------------------------------------------------------*/

 /* Reset of all peripherals, Initializes the Flash interface and the Systick. */

 HAL_Init();

 /* USER CODE BEGIN Init */

 /* USER CODE END Init */

 /* Configure the system clock */

 SystemClock_Config();

/* Configure the peripherals common clocks */

 PeriphCommonClock_Config();

 /* USER CODE BEGIN SysInit */

 /* USER CODE END SysInit */

 /* Initialize all configured peripherals */

 MX_GPIO_Init();

 MX_DMA_Init();

 MX_ADC1_Init();

 MX_ADC2_Init();

 MX_ADC3_Init();

 MX_SPI1_Init();

 MX_SPI3_Init();

 MX_SPI4_Init();

 MX_TIM1_Init();

 MX_TIM2_Init();

 MX_TIM4_Init();

 MX_TIM8_Init();

 MX_USART1_UART_Init();

 MX_USART2_UART_Init();

 MX_USART3_UART_Init();

 /* USER CODE BEGIN 2 */

 //=============================================================

 //TIM1_CH1

 HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);

 HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_1); // turn on complementary channel

 //TIM1_CH2

 HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2);

 HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_2); // turn on complementary channel

 //TIM1_CH3

 HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_3);

 HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_3); // turn on complementary channel

//=============================================================

 //TIM8_CH1

  HAL_TIM_PWM_Start(&htim8, TIM_CHANNEL_1);

  HAL_TIMEx_PWMN_Start(&htim8, TIM_CHANNEL_1); // turn on complementary channel

  //TIM8_CH2

  HAL_TIM_PWM_Start(&htim8, TIM_CHANNEL_2);

  HAL_TIMEx_PWMN_Start(&htim8, TIM_CHANNEL_2); // turn on complementary channel

  //TIM8_CH3

  HAL_TIM_PWM_Start(&htim8, TIM_CHANNEL_3);

  HAL_TIMEx_PWMN_Start(&htim8, TIM_CHANNEL_3); // turn on complementary channel

 //initial PWM Setup

TIM1->CCR1 = 32767;

TIM1->CCR2 = 32767;

TIM1->CCR3 = 32767;

TIM8->CCR1 = 32767;

TIM8->CCR2 = 32767;

TIM8->CCR3 = 32767;

// ADC_DMA Startup

// HAL_ADC_Start_DMA(&hadc1, buffer, 4); // handle ADC1 -> Save to BUFFER value

//  TIM1->CCR1= 32767; // for ADC_TRIGGER TIM1-CCR1 NO OUTPUT |OR| TIM1_CCR1 USE AS PWM

HAL_TIM_Base_Start_IT(&htim1) ;

// IMPORTANT -> void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) for the update event

//HAL_TIM_OC_Start_IT(&htim1, TIM_CHANNEL_1); // Activate the TIM peripheral

// IMPORTANT -> void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim) for the compare event

// ADC calib

// not corect ?? while(HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED) != HAL_OK);

// ================ ADC_DMA ===============================================

if (HAL_ADC_Start_DMA(&hadc1, (uint32_t *)ADC_DATA, ADC_CONVERTED_DATA_BUFFER_SIZE) != HAL_OK)

{

Error_Handler();

}

if (HAL_ADC_Start_DMA(&hadc2, (uint32_t *)ADC_DATA_2, ADC_CONVERTED_DATA_BUFFER_SIZE) != HAL_OK)

{

Error_Handler();

}

if (HAL_ADC_Start_DMA(&hadc3, (uint32_t *)ADC_DATA_3, ADC_CONVERTED_DATA_BUFFER_SIZE) != HAL_OK)

{

Error_Handler();

}

// ================ ADC_DMA ===============================================

TIM1->ARR = 39999/2;

TIM1->CCR1= 0.5* 39999/2;

 /* USER CODE END 2 */

 /* Infinite loop */

 /* USER CODE BEGIN WHILE */

 while (1)

 {

  /* USER CODE END WHILE */

 while_function();

  /* USER CODE BEGIN 3 */

 }

 /* USER CODE END 3 */

}

14 REPLIES 14
MasterT
Lead

I opened your project in CubeMX, issues:

  1. All timers do not have clock sources , though they are all in stop mode.
  2. Timer-1 (to be able to activate ADC conversion) has to be configured /routed PWM channel-1 as external events
  3. ADC is running at 75 /4 = ~18.75 MHz, far away from max speed.

Dear  Master T

Thank you for your kind reply,

After checking your kind comments, I have fixed some function

  1. All timers clock sources are internal now, and it still guaranteed 10KHz Timer switching frequency 0693W00000CzuKqQAJ.png

P/S: actually it does not affect the ADC trigger

2.) Timer-1 (to be able to activate ADC conversion) has to be configured /routed PWM channel-1 as external events

-> I may not understand fully your meaning? in my testing if TIM1. CCR1 =0 -> ADC is not triggered

when TIM1. CCR1 =500 for example, TIM1 PWM have duty >0 then it triggers ADC

-> configured /routed PWM channel-1 as external events would you please show me which parameter that I have to config

0693W00000CzuLyQAJ.png 

3.ADC is running at 75 /4 = ~18.75 MHz, far away from max speed.

-> Thank for your guidance

0693W00000CzuM3QAJ.pngAfter reducing the ADC clock divider, it does improve the ADC performance, but it is not much

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) //

{

 if(hadc->Instance == ADC3) // ADC 3 is the lastest one that trigger the HAL_ADC_ConvCpltCallback

 {

.......................................

}

}

With the config last time 75 /4 = ~18.75 MHz, -> we have the ADC GPIO trigger at 20us

With your suggestion , 75 /2 = ~18.75 *2 MHz, -> we have the ADC GPIO trigger at 15us

However, it is not much high as I expected, Could you please tell me which thing that I should modify?

Here is the modified project one https://1drv.ms/u/s!AuUAN7PWAxFS8l7QfX5_LVRjLFHI?e=Nj7q6Y

Thank you for your kind reply,

I am a new guy in this field so I may not fully understand your meaning?

Here's the thing I found:

because I config ADC 1,2 and 3, there are three DMA-ADC callbacks -> when the ADC data is finished transferred to DMA

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) //

{

 if(hadc->Instance == ADC3) // ADC 3 is the lastest one that trigger the HAL_ADC_ConvCpltCallback

 {

.......................................

}

}

I mean (hadc->Instance =ADC1) will be call first , then (hadc->Instance =ADC2), and finally , (hadc->Instance =ADC3)

because I used the DEBUG function, it seem like (I guess) each "​ HAL_ADC_ConvCpltCallback" equivalent to (hadc->Instance =ADC1), (hadc->Instance =ADC2), and (hadc->Instance =ADC3) have a delay like 5us - Just I feel when I tried to modify the code to see the the difference.

Would you please explain your idea more detail ??

2). Check this out:

Advanced-control timers (TIM1/TIM8) RM0433 (page 1588/3289 RM0433 Rev 6)

37.3.27 ADC synchronization

The timer can generate an ADC triggering event with various internal signals, such as reset,

enable or compare events. It is also possible to generate a pulse issued by internal edge

detectors, such as:

– Rising and falling edges of OC4ref

– Rising edge on OC5ref or falling edge on OC6ref

The triggers are issued on the TRGO2 internal line which is redirected to the ADC. There is

a total of 16 possible events, which can be selected using the MMS2[3:0] bits in the

TIMx_CR2 register.

0693W00000CzujgQAB.png

Thank you for your fast reply,

As a dummy in STM32, I will need more time to read by myself and understand your kind comment,

I will read RM0433 Rev 6

sincerely,