cancel
Showing results for 
Search instead for 
Did you mean: 

Query regarding the nuances of encoder mode

Hrishikesh
Senior

Hi, I have an incremental encoder with 2400 counts per rev that is connected to a ball screw with a pitch of 5mm. I'm trying to accumulate the total count which I then use to calculate the exact distance of the object attached to the ballscrew. I've configured the hardware encoder mode and I'm counting on both edges of both pulses. To keep track of overflows and underflows I'm generating an interrupt everytime the ARR, which is I've set to 2399, overflows. In the subsequent PeriodElapsedCallback function I keep track of the number of revolutions.

For the most part this works except that on startup, the 'rotation_count' variable automatically becomes 1 even with no rotation of the encoder or the PeriodElapsedCallback function being called. Why does this happen? I'm using a STM32407VGx (STM32F4-DISCOVERY board).

uint32_t current_count = 0;
uint32_t rotation_count = 0;
uint32_t total_count = 0;
 
TIM_HandleTypeDef htim1;
 
int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_TIM1_Init();
 
  HAL_TIM_Encoder_Start(&htim1, TIM_CHANNEL_ALL); //Start the encoder mode
  HAL_TIM_Base_Start_IT(&htim1); //Call the HAL_TIM_PeriodElapsedCallback when the ARR value overflows or underflows
 
  while (1)
  {
	  get_encoder_count();
	  HAL_Delay(10);
  }
}
 
void get_encoder_count(void)
{
	current_count = __HAL_TIM_GET_COUNTER(&htim1);
	total_count = (rotation_count * __HAL_TIM_GET_AUTORELOAD(&htim1)) + current_count;
}
 
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  if (htim->Instance == TIM1)
  {
	  __HAL_TIM_IS_TIM_COUNTING_DOWN(&htim1) ? rotation_count-- : rotation_count++;
	  // Use the DIR bit to determine if the encoder is spinning CW or CCW
	  // Since we are in this function because the timer over/under flowed
	  // Increment or decrement the revolution count
  }
}
 
/* TIM1 init function */
void MX_TIM1_Init(void)
{
  TIM_Encoder_InitTypeDef sConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};
 
  htim1.Instance = TIM1;
  htim1.Init.Prescaler = 0;
  htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim1.Init.Period = (2400 - 1);
  htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim1.Init.RepetitionCounter = 0;
  htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  sConfig.EncoderMode = TIM_ENCODERMODE_TI12;
  sConfig.IC1Polarity = TIM_ICPOLARITY_RISING;
  sConfig.IC1Selection = TIM_ICSELECTION_DIRECTTI;
  sConfig.IC1Prescaler = TIM_ICPSC_DIV1;
  sConfig.IC1Filter = 0;
  sConfig.IC2Polarity = TIM_ICPOLARITY_RISING;
  sConfig.IC2Selection = TIM_ICSELECTION_DIRECTTI;
  sConfig.IC2Prescaler = TIM_ICPSC_DIV1;
  sConfig.IC2Filter = 0;
  if (HAL_TIM_Encoder_Init(&htim1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
 
}
 
void HAL_TIM_Encoder_MspInit(TIM_HandleTypeDef* tim_encoderHandle)
{
 
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(tim_encoderHandle->Instance==TIM1)
  {
  /* USER CODE BEGIN TIM1_MspInit 0 */
 
  /* USER CODE END TIM1_MspInit 0 */
    /* TIM1 clock enable */
    __HAL_RCC_TIM1_CLK_ENABLE();
  
    __HAL_RCC_GPIOE_CLK_ENABLE();
    /**TIM1 GPIO Configuration    
    PE9     ------> TIM1_CH1
    PE11     ------> TIM1_CH2 
    */
    GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_11;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF1_TIM1;
    HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
 
    /* TIM1 interrupt Init */
    HAL_NVIC_SetPriority(TIM1_UP_TIM10_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(TIM1_UP_TIM10_IRQn);
  /* USER CODE BEGIN TIM1_MspInit 1 */
 
  /* USER CODE END TIM1_MspInit 1 */
  }
}

1 ACCEPTED SOLUTION

Accepted Solutions
TDK
Guru

I know you said it's not, but the most likely scenario is that HAL_TIM_PeriodElapsedCallback is getting called immediately when the timer is started because the UIF bit gets set during initialization.

You can fix this by clearing this bit after the timer is initialized by calling __HAL_TIM_CLEAR_IT(&htim1, TIM_IT_UPDATE); before enabling the update interrupt.

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

View solution in original post

2 REPLIES 2
TDK
Guru

I know you said it's not, but the most likely scenario is that HAL_TIM_PeriodElapsedCallback is getting called immediately when the timer is started because the UIF bit gets set during initialization.

You can fix this by clearing this bit after the timer is initialized by calling __HAL_TIM_CLEAR_IT(&htim1, TIM_IT_UPDATE); before enabling the update interrupt.

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

This helped. Thank you.