cancel
Showing results for 
Search instead for 
Did you mean: 

Stm32 Encoder interface

cheeleong_clwai
Associate II
Posted on July 12, 2011 at 11:20

Nid help in Stm32 Encoder Interface, to turn the motor in clockwise and anti-clockwise direction. Thanks 

#encoder-interface #stm32f0-discovery
6 REPLIES 6
ivanov-i2
Associate II
Posted on July 12, 2011 at 16:20

Do you have any specific problem? Did you try to do it by yourself?

I doubt that controlling the motor will requre something more than just configuring a timer as an encoder interface.

cheeleong_clwai
Associate II
Posted on July 14, 2011 at 05:51

Yes, i've tried doing it myself but the motor will keep on turning indefinitely. I was hoping that it could turn in both direction, but i cant manage to do it. I'm new to STM32, sorry for the stupid question. Thanks

int main(void)

{

#ifdef DEBUG

debug();

#endif

/* System Clocks Configuration */

RCC_Configuration();

/* NVIC Configuration */

NVIC_Configuration();

/* GPIO Configuration */

GPIO_Configuration();

/* Time base configuration */

TIM_TimeBaseStructure.TIM_Period = 999;

TIM_TimeBaseStructure.TIM_Prescaler = 0;

TIM_TimeBaseStructure.TIM_ClockDivision = 0;

TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);

/* PWM1 Mode configuration: Channel1 */

TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;

TIM_OCInitStructure.TIM_Channel = TIM_Channel_1;

TIM_OCInitStructure.TIM_Pulse = CCR1_Val;

TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;

TIM_OCInit(TIM3, &TIM_OCInitStructure);

TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);

/* PWM1 Mode configuration: Channel2 */

TIM_OCInitStructure.TIM_Channel = TIM_Channel_2;

TIM_OCInitStructure.TIM_Pulse = CCR2_Val;

TIM_OCInit(TIM3, &TIM_OCInitStructure);

TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);

/* PWM1 Mode configuration: Channel3 */

TIM_OCInitStructure.TIM_Channel = TIM_Channel_3;

TIM_OCInitStructure.TIM_Pulse = CCR3_Val;

TIM_OCInit(TIM3, &TIM_OCInitStructure);

TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable);

/* PWM1 Mode configuration: Channel4 */

TIM_OCInitStructure.TIM_Channel = TIM_Channel_4;

TIM_OCInitStructure.TIM_Pulse = CCR4_Val;

TIM_OCInit(TIM3, &TIM_OCInitStructure);

TIM_OC4PreloadConfig(TIM3, TIM_OCPreload_Enable);

TIM_ARRPreloadConfig(TIM3, ENABLE);

/* TIM3 enable counter */

TIM_Cmd(TIM3, ENABLE);

GPIO_SetBits(GPIOB, GPIO_Pin_2);

// Pb2 |= 0x80;

// Pb2 &=~0xC0;

while (1)

{

}

}

void RCC_Configuration(void)

{

/* RCC system reset(for debug purpose) */

RCC_DeInit();

/* Enable HSE */

RCC_HSEConfig(RCC_HSE_ON);

/* Wait till HSE is ready */

HSEStartUpStatus = RCC_WaitForHSEStartUp();

if(HSEStartUpStatus == SUCCESS)

{

/* Enable Prefetch Buffer */

FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);

/* Flash 2 wait state */

FLASH_SetLatency(FLASH_Latency_2);

/* HCLK = SYSCLK */

RCC_HCLKConfig(RCC_SYSCLK_Div1);

/* PCLK2 = HCLK */

RCC_PCLK2Config(RCC_HCLK_Div1);

/* PCLK1 = HCLK/4 */

RCC_PCLK1Config(RCC_HCLK_Div4);

/* PLLCLK = 8MHz * 9 = 72 MHz */

RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);

/* Enable PLL */

RCC_PLLCmd(ENABLE);

/* Wait till PLL is ready */

while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)

{

}

/* Select PLL as system clock source */

RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

/* Wait till PLL is used as system clock source */

while(RCC_GetSYSCLKSource() != 0x08)

{

}

}

/* TIM3 clock enable */

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);

/* GPIOA and GPIOB clock enable */

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE);

}

void GPIO_Configuration(void)

{

GPIO_InitTypeDef GPIO_InitStructure;

/*GPIOA Configuration: TIM3 channel 1 and 2 */

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOA, &GPIO_InitStructure);

/*GPIOB Configuration: TIM3 channel 3 and 4 */

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

//GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;

// GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

GPIO_Init(GPIOB, &GPIO_InitStructure);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2|GPIO_Pin_11|GPIO_Pin_0;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

GPIO_Init(GPIOB, &GPIO_InitStructure);

}

void NVIC_Configuration(void)

{

#ifdef VECT_TAB_RAM

/* Set the Vector Table base location at 0x20000000 */

NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);

#else /* VECT_TAB_FLASH */

/* Set the Vector Table base location at 0x08000000 */

NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);

#endif

}

#ifdef DEBUG

void assert_failed(u8* file, u32 line)

{

/* User can add his own implementation to report the file name and line number,

ex: printf(''Wrong parameters value: file %s on line %d\r\n'', file, line) */

while (1)

{ GPIO_SetBits(GPIOB, GPIO_Pin_2);

GPIO_SetBits(GPIOB, GPIO_Pin_11);

GPIO_SetBits(GPIOB, GPIO_Pin_0);

}

}

#endif

________________

Attachments :

encoder_interface.png : https://st--c.eu10.content.force.com/sfc/dist/version/download/?oid=00Db0000000YtG6&ids=0680X000006I0wW&d=%2Fa%2F0X0000000bfw%2FBvJ36YTloKcpEY8ykHWkiuV9Z.Fh2YWq_M0jLqCzPzk&asPdf=false
ivanov-i2
Associate II
Posted on July 18, 2011 at 15:30

Ryuk, if I understand correctly what you intend to do is a position control of the motor - otherwise, there is no big sense to use an encoder. Of course, the encoder is also suitable for motor speed control.

In any case you should use some kind of feedback (PID loop) to achieve this. It is a piece of software, which is called periodically (say every 1 to 10 ms), which compares the measured value with the setpoint variable and produces a suitable control output. If you are new in the control world there is a lot of stuff in the net about PID, feedback, motor control, etc.

Regarding setting of the timer as an encoder counter you need to do:

- enable timer clock in RCC_APB1ENR register

- set SMS field in TIM3SMCR to 3

- set CC1S in TIM3_CCMR1 to 1

- set CC2S in TIM3_CCMR1 to 1

- enable the timer (CEN in TIM3_CR1)

I would've also use a timer reload value of 0xFFFF (TIM3_ARR) because this is the natural overflow point of 16-bit variable and it is handled easier by the software.

kasun_duminda92
Associate III
Posted on July 26, 2013 at 05:03

I have some questions on this topic. I am using STM32F0 Discovery.

I have a motor with a quadrature encoder and I want to get the relative (absolute after counting from home position) position. I tried getting the encoder count using an interrupt from one channel of the encoder and checking the state of the other channel. But I found that a lot of counts are missed when the encoders are interfaced this way.

Now I have decided to try the Encoder Interface. The Reference manual says that I don't need 'external interface logic' to connect the encoder so I think I can directly connect the encoder channels to the STM32F0 (0-3V).  I have seen the Encoder mode example for the STM32F0 but cannot fully understand how to implement it.

What is the maximum value the timer can count upto? Should I set this value? Which pins correspond to the encoder interface? What register or variable do I read to get the encoder count?

Posted on July 26, 2013 at 05:50

Most of the timers are 16-bit, so 0-65535 maximal, TIM2 is 32-bit so 0-0xFFFFFFFF, or whatever you set the Period too.

The Encoder interface expects the two quadrature signals on CH1 and CH2 of the TIM you choose.

The pin assignments will depend on the TIM chosen, review the Data Manual for your part, it has a list, use that as your guide.

The ONLY counting element of the timer is the CNT register, this is where your position will be. The Reference Manual has a block diagram of the TIM unit.
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
kasun_duminda92
Associate III
Posted on August 31, 2013 at 16:10

Thank you clive1.