cancel
Showing results for 
Search instead for 
Did you mean: 

Strange delays when changing PWM using Circular DMA

carleslsregner
Associate III

Hello world!

I want to move a motor with serial commands. I use the stm32g051 PWM and a DC motor. And for the sake of lower consumption of energy and cpu I use a dma in circular mode. And of course I want to change the pwm from time to time. 

But somehow, there is always a delay of more than 10 seconds between the calling of the function and the change in the motor behaviour. 

mid_error_t tim_forward_buffers(void)
{

	for (uint16_t i=0; i<PWM_BUF_LEN; i++){
		pwm_ch1[i] =  (uint32_t)(param.speed * (htim2.Init.Period-2))/ MAX_SPEED;
		//pwm_ch1[i] = 0; // htim2.Init.Period;
		pwm_ch2[i] = 0;
	}
	__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, pwm_ch1[0]);
	__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2, pwm_ch2[0]);

	return MID_ERROR_OK;
}

You may guess that the PWM_BUF_LEN is too big... There is just one element in pwm_ch1 and pwm_ch2. What may cause this problem? 

I use the __HAL_TIM_SET_COMPARE to change the pwm faster and the pwm_ch1 pwm_ch2 just contain one element so the DMA doesn't have to wait to change it.

 

 

 

1 ACCEPTED SOLUTION

Accepted Solutions
waclawek.jan
Super User

> there is always a delay of more than 10 seconds between the calling of the function and the change in the motor behaviour

How do you know? How do you observe the point in time when the function is called? 

Have you measured the actual PWM output?

> I use the __HAL_TIM_SET_COMPARE to change the pwm faster and the pwm_ch1 pwm_ch2 just contain one element so the DMA doesn't have to wait to change it.

...and still it takes 10 seconds until the effect?

JW

View solution in original post

5 REPLIES 5
KnarfB
Super User

My guess: the timer period is long.
Changing the compare value has no immediate effect, but is buffered in a shadow register and updated at the next update event.  You may force update by

TIM2->CCR1 = new_value;
TIM2->EGR |= TIM_EGR_UG; // force update event

or disable buffering in advance:

TIM2->CCMR1 &= ~TIM_CCMR1_OC1PE; // for channel 1

hth

KnarfB

carleslsregner
Associate III

I am going to change the timer period -I guess it is the pwm period too-.

 

 

/* TIM2 init function */
/**
 * @brief Initialize TIM2 for PWM generation on channels 1 and 2 with DMA support
 */
mid_error_t MX_TIM2_Init(void)
{

  /* USER CODE BEGIN TIM2_Init 0 */

  /* USER CODE END TIM2_Init 0 */

  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_OC_InitTypeDef sConfigOC = {0};

  /* USER CODE BEGIN TIM2_Init 1 */

  /* USER CODE END TIM2_Init 1 */
  htim2.Instance = TIM2;
  htim2.Init.Prescaler = 3;
  htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim2.Init.Period = 399; // 20kHz PWM frequency with 64MHz timer clock
  htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
  if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
  {
   return MID_ERROR_FAILED_INIT;
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
  {
    return MID_ERROR_FAILED_INIT;
  }
  if (HAL_TIM_PWM_Init(&htim2) != HAL_OK)
  {
	    return MID_ERROR_FAILED_INIT;
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
  {
	  return MID_ERROR_FAILED_INIT;
  }
  sConfigOC.OCMode = TIM_OCMODE_PWM1;
  sConfigOC.Pulse = 0;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
  {
	  return MID_ERROR_FAILED_INIT;
  }
  if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
  {
	  return MID_ERROR_FAILED_INIT;
  }
  /* USER CODE BEGIN TIM2_Init 2 */

  /* USER CODE END TIM2_Init 2 */
  HAL_TIM_MspPostInit(&htim2);

//   if( tim_brake_buffers() != MID_ERROR_OK) // brake by default
//   {
//	   return MID_ERROR_FAILED_INIT;
//   }






  HAL_TIM_PWM_Start_DMA(&htim2, TIM_CHANNEL_1, pwm_ch1, PWM_BUF_LEN);
  HAL_TIM_PWM_Start_DMA(&htim2, TIM_CHANNEL_2, pwm_ch2, PWM_BUF_LEN);

  return MID_ERROR_OK;

}

 

TDK
Super User

I don't see anything wrong with the posted code. I would recheck your assumptions here.

> //pwm_ch1[i] = 0; // htim2.Init.Period;

This is not the "Period" parameter. It's the "pulse" parameter.

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

> there is always a delay of more than 10 seconds between the calling of the function and the change in the motor behaviour

How do you know? How do you observe the point in time when the function is called? 

Have you measured the actual PWM output?

> I use the __HAL_TIM_SET_COMPARE to change the pwm faster and the pwm_ch1 pwm_ch2 just contain one element so the DMA doesn't have to wait to change it.

...and still it takes 10 seconds until the effect?

JW

carleslsregner
Associate III

My guess is that this is a hardware issue... it seems related to the elecrtonics behind it. 

Thanks you all.