Skip to main content
pccasio
Associate
February 26, 2021
Solved

High speed error with encoder, STM32F103

  • February 26, 2021
  • 6 replies
  • 1871 views

Hello,

We are using an encoder ( https://www.andymark.com/products/redline-encoder-kit ) with 4096 CPR and are trying to measure speed and direction of a motor with an STM32F103. However, we cannot read stable values and in high frequencies we cannot read at all. Currently, our MCU is working on 72 MHz frequency and in TIM2 we are using the Encoder mode with interrupt. (Prescaler value=0, Counter period value=65535)

Should we use the DMA as well? Would it make any difference? Do you have any suggestions on what improvements we could make to our system?

Below is our snippet of user code regarding the issue.

Thanks in advance.

*EDIT: Updated the prescaler and counter period value

typedef struct encoderStruct {
	uint32_t counter_u32;
	_Bool measuredDirection_bool;
	float measuredSpeed_f32;
}ENCODER_HandleTypeDef;
 
// ***
void Measure_Speed(TIMER_HandleTypeDef *timer, FLAG_HandleTypeDef *flag, ENCODER_HandleTypeDef *encoder){
	if(TIM2->CR1 == 1) {
		encoder->measuredDirection_bool = 0;
		encoder->counter_u32 = (uint32_t)(TIM2->CNT);
		if(timer->velocityCalculator_u16 > VELOCITY_TIME) {
			TIM2->CNT = 0;
			encoder->measuredSpeed_f32 = ((float)encoder->counter_u32 / ENCODER_PULS) * 60.0;
			timer->velocityCalculator_u16 = 0;
			flag->LED.motorForward_bit = 1;
			flag->LED.motorBackward_bit = 0;
		}
	} else if(TIM2->CR1 == 17) {
		encoder->measuredDirection_bool = 1;
		encoder->counter_u32 = 65535 - (uint32_t)TIM2->CNT;
		if(timer->velocityCalculator_u16 > VELOCITY_TIME) {
			TIM2->CNT = 65535;
			encoder->measuredSpeed_f32 = ((float)encoder->counter_u32 / ENCODER_PULS) * 60.0;
			timer->velocityCalculator_u16 = 0;
			flag->LED.motorForward_bit = 0;
			flag->LED.motorBackward_bit = 1;
		}
	}
}
 
//***
HAL_TIM_Encoder_Start_IT(&htim2, encoderA_Pin);
HAL_TIM_Encoder_Start_IT(&htim2, encoderB_Pin);

This topic has been closed for replies.
Best answer by pccasio

Alright, we converted it to 32-bit and now it seems to be reading stable values. Thanks a lot for the suggestion!

6 replies

Uwe Bonnes
Chief
February 26, 2021

Rethink your concept. The encoder is meant to run free. For speed measurement, sample the TIM2 value and calculate the difference/

pccasio
pccasioAuthor
Associate
February 26, 2021

What do you mean by encoder being meant to run free? And what exactly should we calculate the difference of? Could you please rephrase your suggestion as I did not quite understand it.

Still, thanks for your attention.

waclawek.jan
Super User
February 26, 2021

Never use prescaler with Encoder mode.

Set ARR ("Period") to maximum value, never change CNT, and, as Uwe said, for speed calculation, subtract values read out of CNT at subsequent timing points.

JW

pccasio
pccasioAuthor
Associate
February 26, 2021

The prescaler and the period given in the question was not for the encoder but I updated it as you said, however we still have the same problems. Also, we are already doing that subtraction. Could we use the DMA as well?

Thanks for your answer, and sorry for the trouble.

waclawek.jan
Super User
February 26, 2021

Read it and post content of encoder timer registers.

What are the values you read? Isn't TIM2 a 32-bit timer, i.e. why restricting it to 16 bits?

JW

pccasio
pccasioAuthorBest answer
Associate
February 26, 2021

Alright, we converted it to 32-bit and now it seems to be reading stable values. Thanks a lot for the suggestion!