cancel
Showing results for 
Search instead for 
Did you mean: 

Control amount of samples for timer STM32H7 via PWM?

Ronil
Senior

Hello, I need to make 10 samples via Tim13 and PWM in STM32H7. I implemented the next script, but finally, on the oscilloscope, I saw about 50 samples every 0.1 sec. Do you know, how easily control the number of samples for Timer in stm32?

 

 

 

#include "main.h"
TIM_HandleTypeDef htim13;
void SystemClock_Config(void);
static void MPU_Config(void);
static void MX_GPIO_Init(void);
static void MX_TIM13_Init(void);

int main(void)
{
  MPU_Config();
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_TIM13_Init();

uint32_t sample_counter = 0;
#define SAMPLE_COUNT 10

TIM13->PSC = 0;       // No prescaling
TIM13->ARR = 1;       // Minimum possible period
TIM13->CCR1 = 1;      // 50% duty cycle
TIM13->RCR = 0;       // No repetition
TIM13->CCMR1 |= (6 << 4);// PWM Mode 1 (not 2, as we want the output to be high when CNT < CCR1)
TIM13->CR1 &= ~TIM_CR1_OPM;  // Disable One-pulse mode (we want continuous operation)
TIM13->CCER |= 1;  // Capture/Compare 1 Enable
TIM13->BDTR |= TIM_BDTR_MOE;  // Master Output enable
TIM13->CR1 |= TIM_CR1_CEN;  // Enable the counter

while (1)
{
    if (sample_counter < SAMPLE_COUNT)
    {
        TIM13->CR1 |= TIM_CR1_CEN;  // Enable the counter
        while(!(TIM13->SR & TIM_SR_UIF)){}  // Wait for update event
         TIM13->SR &= ~1;  // Clear the update event flag
        sample_counter++;  // Increment the sample counter
    }
    else
    {
        TIM13->CR1 &= ~TIM_CR1_CEN;  
        HAL_Delay(0.1);
        sample_counter = 0;
    }
}

}

void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  HAL_PWREx_ConfigSupply(PWR_LDO_SUPPLY);

  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
  while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}
  __HAL_RCC_SYSCFG_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE0);

  while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}

  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_DIV1;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLM = 4;
  RCC_OscInitStruct.PLL.PLLN = 50;
  RCC_OscInitStruct.PLL.PLLP = 2;
  RCC_OscInitStruct.PLL.PLLQ = 4;
  RCC_OscInitStruct.PLL.PLLR = 2;
  RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_3;
  RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
  RCC_OscInitStruct.PLL.PLLFRACN = 0;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2
                              |RCC_CLOCKTYPE_D3PCLK1|RCC_CLOCKTYPE_D1PCLK1;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;
  RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}

static void MX_TIM13_Init(void)
{
  TIM_OC_InitTypeDef sConfigOC = {0};
  htim13.Instance = TIM13;
  htim13.Init.Prescaler = 0;
  htim13.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim13.Init.Period = 1;
  htim13.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim13.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
  if (HAL_TIM_Base_Init(&htim13) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_PWM_Init(&htim13) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_OnePulse_Init(&htim13, TIM_OPMODE_SINGLE) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigOC.OCMode = TIM_OCMODE_PWM1;
  sConfigOC.Pulse = 1;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_ENABLE;
  if (HAL_TIM_PWM_ConfigChannel(&htim13, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
  {
    Error_Handler();
  }
  HAL_TIM_MspPostInit(&htim13);
}


 

 

 

1 ACCEPTED SOLUTION

Accepted Solutions

Created new project in CubeMX. Put the following statements in the main loop:

HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
HAL_Delay(100);

And it gives the correct number of pulses. 11 in this case because i set RCR=10.

TDK_1-1725026950801.png

This is a bit cleaner with register access where all you have to do to send another pulse train is enable the timer:

SET_BIT(TIM1->CR1, TIM_CR1_CEN);

 

 

From your code:

> HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
> HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_1);

Don't stop the PWM immediately after you start it.

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

View solution in original post

8 REPLIES 8
TDK
Guru

For high speed pulses, which you have here, you're going to need to do it in hardware with the RCR register = 10 and with the timer in one pulse mode. If you set those up, and then enable the timer, it will do 10 pulses and disable when complete. Software is not going to be quick enough to stop after the last pulse and before the next one begins.

 

However, TIM13 doesn't have an RCR register, so you'll need to swap to a timer that does (TIM1, 8, 16, 17)

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

thank you for your message. I started to use timer 1 with the next settings but didn't receive any result

 

  htim1.Instance = TIM1;
  htim1.Init.Prescaler = 0;
  htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim1.Init.Period = 1;
  htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim1.Init.RepetitionCounter = 10;
  htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;

 

 in one pulse mode and without 

with the next script I expected to see 10 samples, but actually it doesn't work like that

 

  MX_TIM1_Init();
  while (1)
  {
    /* USER CODE END WHILE */
      HAL_Delay(0.1);
  	  HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
  	  HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_1);

    /* USER CODE BEGIN 3 */
  }

 

Do you know what I did wrong?
Actually I am not sure that  RCR register responsible for that 

Did you use one pulse mode?

(++) HAL_TIM_OnePulse_Init and HAL_TIM_OnePulse_ConfigChannel: to use the Timer
in One Pulse Mode.

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

Yes, I tried both, with one pulse mode is active I only get 1 pulse instead of 10

Created new project in CubeMX. Put the following statements in the main loop:

HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
HAL_Delay(100);

And it gives the correct number of pulses. 11 in this case because i set RCR=10.

TDK_1-1725026950801.png

This is a bit cleaner with register access where all you have to do to send another pulse train is enable the timer:

SET_BIT(TIM1->CR1, TIM_CR1_CEN);

 

 

From your code:

> HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
> HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_1);

Don't stop the PWM immediately after you start it.

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

Indeed. if I correctly undestand that I can use only timers with RCR

Also, what do you think about fluctuation after the timer is running out?New Bitmap Image.jpg

LCE
Principal

That's no "fluctuation", it's called overshoot.

It's probably due to bad scope-probe setup. For frequencies > 100kHz do NOT use the probe's GND cable, but a spring tip for GND directly attached to the probe's tip.

What's the time scale of that scope pic? Can't really say if it's 20 ms or ns per division. If it's ms, then forget everything above, them you have some other circuit-related problem (load?), or configured the GPIO not correctly.

 

thank you! I measure 100 Mhz