cancel
Showing results for 
Search instead for 
Did you mean: 

Reading Encoder pulses using external interrupts

NSure.1
Associate

I'm using STM32L451VCI6 MCU to read pulses from a rotary encoder attached to the shaft of a stepper motor using external interrupts. I'm incrementing a counter at rising edge of interrupt.

According to spec of the encoder, I should be able to read 400 pulses per revolution. but for lower speeds, the count pulses are more than expected. Am I reading the pulses wrong?

This is how I run the motor

HAL_GPIO_WritePin(GPIOA, Direction_Pin, GPIO_PIN_RESET);  

for(int i=0;i<200;i++)

 

{

HAL_GPIO_WritePin(GPIOA, M1_STP_Pin, GPIO_PIN_SET);

delay_us(900);

HAL_GPIO_WritePin(GPIOA, M1_STP_Pin, GPIO_PIN_RESET);

delay_us(900);

 }

void delay_us (uint32_t us)

{

__HAL_TIM_SET_COUNTER(&htim1,0); 

while (((uint16_t)__HAL_TIM_GET_COUNTER(&htim1)) < us);

//uint32_t p = TIM1->CNT;

}

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)

{

if(GPIO_Pin == ENC_A_Pin)

{

if(HAL_GPIO_ReadPin(GPIOA, ENC_A_Pin) == GPIO_PIN_SET)

{

counter++;

}

}

}

For delays less than 900us, I'm getting 400 counts/rotation. But not for 900 or greater. Any help is appreciated

3 REPLIES 3
S.Ma
Principal

Try ti use hw to implement rotary encoder without any sw delay. I can guess use a timer to use precise time scan period say 1 khz, then use exti PR bit that capture rise and fall edge on new stm32 families, or use input capture, even with dma, taking sw care of timer overflow for long and slow wheel turns. If low power modes are involved, some ways maybe better than others, and involves interrupts.

Aren't their simpler, cleaner methods of counting of counts on a TIM?

What's the configuration of TIM1 actually look like?

At lower speeds the interrupt perhaps isn't masking off bouncing

How are you determining each revolution?

Could you count pulses on ENC_A via a TIM in External Clock mode?

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

Thanks for the response.

Is digital filter implementation a good method for debouncing?

I'm working on a custom board with predefined pin configuration which limits my use of Timers to read the encoder. I need to use external interrupts.

I'm rotating the stepper motor for 1 revolution by supplying 200 steps, and reading the pulses from encoder for that revolution.

The timer is used here to create the microseconds delay for step generation to stepper motor. Timer configuration looks like this. Clock is set to Max (80Mhz)

static void MX_TIM1_Init(void)

 TIM_ClockConfigTypeDef sClockSourceConfig = {0};

 TIM_MasterConfigTypeDef sMasterConfig = {0};

 htim1.Instance = TIM1;

 htim1.Init.Prescaler = 80-1;

 htim1.Init.CounterMode = TIM_COUNTERMODE_UP;

 htim1.Init.Period = 65535;

 htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;

 htim1.Init.RepetitionCounter = 0;

 htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;

 if (HAL_TIM_Base_Init(&htim1) != HAL_OK)

 {

  Error_Handler();

 }

 sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;

 if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != 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();

 }

}