cancel
Showing results for 
Search instead for 
Did you mean: 

Count on Tim2 going past ARR?

SWenn.1
Senior III

I have a simple example where I take an A/D sample from a pot every 15ms. I then modify CCR1-4 on both TIM2 and TIM1 AS WELL AS ARR registers on TIM2 and TIM1. ARR is updated with a value and ALL CCRx are updated with that value - #define. I notice that TIM1 works just fine but TIM2 CNT seems to go "out of bounds" past ARR value. The HW is an STM32WB55 that is on a dev board by Midatronics (Sharky Mkr). Both timers are set up identical except for Tim2 missing registers(see below). Can someone tell me what I might be missing here?

Configuration looks like (most of this comes from CubeMx:

static void MX_TIM1_Init(void)
{
 
  /* USER CODE BEGIN TIM1_Init 0 */
 
  /* USER CODE END TIM1_Init 0 */
 
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_OC_InitTypeDef sConfigOC = {0};
  TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};
 
  /* USER CODE BEGIN TIM1_Init 1 */
 
  /* USER CODE END TIM1_Init 1 */
  htim1.Instance = TIM1;
  htim1.Init.Prescaler = 1600 - 1;
  htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim1.Init.Period = pwmPulse[0];			//ALERT CHANGE
  htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim1.Init.RepetitionCounter = 0;
  htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_PWM_Init(&htim1) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterOutputTrigger2 = TIM_TRGO2_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigOC.OCMode = TIM_OCMODE_PWM2;
  sConfigOC.Pulse = pwmPulse[0] - HAPTIC_PW;		//ALERT CHANGE
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
  sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
  if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_3) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_4) != HAL_OK)
  {
    Error_Handler();
  }
  sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
  sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
  sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
  sBreakDeadTimeConfig.DeadTime = 0;
  sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
  sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
  sBreakDeadTimeConfig.BreakFilter = 0;
  sBreakDeadTimeConfig.BreakAFMode = TIM_BREAK_AFMODE_INPUT;
  sBreakDeadTimeConfig.Break2State = TIM_BREAK2_DISABLE;
  sBreakDeadTimeConfig.Break2Polarity = TIM_BREAK2POLARITY_HIGH;
  sBreakDeadTimeConfig.Break2Filter = 0;
  sBreakDeadTimeConfig.Break2AFMode = TIM_BREAK_AFMODE_INPUT;
  sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
  if (HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM1_Init 2 */
 
  /* USER CODE END TIM1_Init 2 */
  HAL_TIM_MspPostInit(&htim1);
 
}
 
/**
  * @brief TIM2 Initialization Function
  * @param None
  * @retval None
  */
static void MX_TIM2_Init(void)
{
 
  /* USER CODE BEGIN TIM2_Init 0 */
 
  /* USER CODE END TIM2_Init 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 = 1600 - 1;
  htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim2.Init.Period = pwmPulse[0];			//ALERT CHANGE
  htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_PWM_Init(&htim2) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigOC.OCMode = TIM_OCMODE_PWM2;
  sConfigOC.Pulse = pwmPulse[0] - HAPTIC_PW;		//ALERT CHANGE
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_3) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_4) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM2_Init 2 */
 
  /* USER CODE END TIM2_Init 2 */
  HAL_TIM_MspPostInit(&htim2);
 
}

Application within the while loop is pretty simple and looks like this:

	if (ISR.A_Conversion)
	{
		volatile uint32_t *pTim1, *pTim2;
		ISR.A_Conversion = F;
 
		speed = Speed(&adcValue[0]);
		TIM1->ARR = pwmPulse[speed];
		TIM2->ARR = pwmPulse[speed];
		pTim1 = &TIM1->CCR1;
		pTim2 = &TIM2->CCR1;
		for (uint8_t i = 0; i < 4; i++)
		{
			*(pTim1 + (i)) = (pwmPulse[speed] - HAPTIC_PW);
			*(pTim2 + (i)) = (pwmPulse[speed] - HAPTIC_PW);
			HAL_TIM_PWM_Start(&htim2, 4*i);
			HAL_TIM_PWM_Start(&htim1, 4*i);
		}
 
	}

5 REPLIES 5
TDK
Guru

The counter is reset when the tick after CNT = ARR. If you modify ARR such that it's now below CNT, the timer never hits this condition and will continue on until it overflows.

You'll need to decide how to handle the current counter, either reset it, or reset it if outside of the new bounds, or something else.

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

Ah yes...thank you!

Can you tell me is there a bit in one of the registers to do such a thing (that is reset CNT when ARR loaded)?

TDK
Guru

I don't think so.

Set CNT=0 immediately after you set ARR if that's what you want.

Note that ARR is preloaded by default so will take effect at the next update event. You can generate an update event which allows it to take effect and resets CNT at the same time.

TIMx->EGR = TIM_EGR_UG;

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

Perfect....Thanks again!

> Note that ARR is preloaded by default

It is not, see TIMx_CR1.ARPE.

Cube could affect this, but it appears that OP chose not to:

> htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;

Would ARR be preloaded, the above effect would never happen - preload is there exactly in order to prevent this effect.

If CCR are updated while timer is running, they should be preloaded, too.

JW