cancel
Showing results for 
Search instead for 
Did you mean: 

Quadrature encoders on STM32F4

michaelmichael9137
Associate II
Posted on April 29, 2013 at 14:47

Hi everyone and thanks in advance for your advices.

I'm using a quadrature encoder from Bourns :

http://www.bourns.com/data/global/pdfs/pecpdf#search=%22PEC11%22

with an STM32F4 chip. I have two questions : - First of all, is it possible to use multiple encoders with a reasonable amount of used pins on the STM32? Maybe with shift registers or dedicated components? I have to implement 9 encoders for my project and I can't use 9 different timers to receive the datas. - My second question is about the code I already wrote. It works and ables me to read the encoder position but when I turn it too fast, it seems that I loose some datas. Any help with that? Here is the code :

#include ''stm32f4xx_gpio.h''
#include ''stm32f4xx_rcc.h''
#include ''stm32f4xx_tim.h''
//-------------------------------------------#DEFINE------------------------------------------
// | TIM4_CH1 pin (PB.06) |
// | TIM4_CH2 pin (PB.07) |
// --------------------------
//PINS CODEUR A ET B
#define Codeur_A GPIO_Pin_6
#define Codeur_A_SOURCE GPIO_PinSource6
#define Codeur_B GPIO_Pin_7
#define Codeur_B_SOURCE GPIO_PinSource7
#define Codeur_GPIO GPIOB
#define Codeur_RCC RCC_AHB1Periph_GPIOB
#define Codeur_AF GPIO_AF_TIM4
//TIMER UTILISE
#define Codeur_TIMER TIM4
#define Codeur_TIMER_CLK RCC_APB1Periph_TIM4
#define Codeur_COUNT() Codeur_TIMER->CNT
//LEDS DEMOBOARD
#define Led_Red GPIO_Pin_12
#define Led_Green GPIO_Pin_14
#define Led_GPIO GPIOD
#define Led_RCC RCC_AHB1Periph_GPIOD
//-------------------------------------------VARIABLES------------------------------------------
//GLOBAL
volatile
int16_t Codeur_count;
volatile
int32_t Codeur_total;
//LOCAL
static
volatile
int16_t Codeur_old;
static
volatile
int16_t Codeur_actual;
//------------------------------------------PROTOTYPES-----------------------------------------
void
RCC_Configuration(
void
);
void
GPIO_Configuration(
void
);
void
TIMER_Configuration(
void
);
void
CODEUR_Reset(
void
);
void
CODEUR_Read(
void
);
//---------------------------------------------MAIN--------------------------------------------
int
main(
void
)
{
//-----VARIABLES-----//
//-----INITIALISATIONS-----//
RCC_Configuration();
GPIO_Configuration();
TIMER_Configuration();
//-----BOUCLE-----//
while
(1)
{
CODEUR_Read();
}
return
0;
}
//-------------------------------------------FONCTIONS-------------------------------------------
void
CODEUR_RESET (
void
)
{
__disable_irq();
Codeur_old = 0;
Codeur_total = 0;
TIM_SetCounter (Codeur_TIMER, 0);
CODEUR_Read();
__enable_irq();
}
void
TIMER_Configuration(
void
)
{
// set them up as encoder inputs
// set both inputs to rising polarity to let it use both edges
TIM_EncoderInterfaceConfig (Codeur_TIMER, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);
TIM_SetAutoreload (Codeur_TIMER, 0xffff);
// turn on the timer/counters
TIM_Cmd (Codeur_TIMER, ENABLE);
// Reset
CODEUR_RESET ();
}
void
CODEUR_Read (
void
)
{
Codeur_old = Codeur_actual;
Codeur_actual = TIM_GetCounter (Codeur_TIMER) ;
Codeur_count = Codeur_actual - Codeur_old;
Codeur_total += Codeur_count;
}
void
RCC_Configuration(
void
)
{
// Enable RCC codeur
RCC_AHB1PeriphClockCmd(Codeur_RCC, ENABLE);
// Enable RCC led
RCC_AHB1PeriphClockCmd(Led_RCC, ENABLE);
// Enable Timer 4 clock
RCC_APB1PeriphClockCmd(Codeur_TIMER_CLK, ENABLE);
}
void
GPIO_Configuration(
void
)
{
GPIO_InitTypeDef GPIO_InitStructure;
// 2 Inputs for A and B Encoder Channels
GPIO_InitStructure.GPIO_Pin = Codeur_A|Codeur_B;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(Codeur_GPIO, &GPIO_InitStructure);
//Timer AF Pins Configuration
GPIO_PinAFConfig(Codeur_GPIO, Codeur_A_SOURCE, Codeur_AF);
GPIO_PinAFConfig(Codeur_GPIO, Codeur_B_SOURCE, Codeur_AF);
// Output Leds
GPIO_InitStructure.GPIO_Pin = Led_Red|Led_Green;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(Led_GPIO, &GPIO_InitStructure);
}

Thanks again. #encoders-stm32f4-multiple #qei #qei
15 REPLIES 15
Posted on April 29, 2013 at 16:08

One could presumably attach external chips via the FSMC, or implement with interrupts via EXTI on GPIO pins.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
emalund
Associate III
Posted on April 29, 2013 at 18:04

never worked with this on these chips, but you do not need a STM32 quadrature encoder, you need a STM32 quadrature decoder,

michaelmichael9137
Associate II
Posted on April 30, 2013 at 14:20

Erik, I'm not sure to see what you meant there.

Clive, concerning the FSMC, I think it always uses a large number of GPIO pins, and that is precisely what I want to avoid. (plus I don't know which external component I should use behind the FSMC to manage these encoders). And the EXTI won't really save me some pins here, because I still have to compare two signals per encoder to decode the sequence. 

I can't find any topic about this issue anywhere. Any more ideas?

Posted on April 30, 2013 at 15:52

Yeah, it sounds like your application is relatively niche. No, I don't see a way of magically multiplexing this information into the part. Perhaps you can use smarter encoders that report their position?

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
jpeacock2399
Associate II
Posted on April 30, 2013 at 16:12

Your biggest problem with using a software QEI is handling the case where an encoder phase stops on an edge, oscillating on and off.  The STM32 handles it by comparing both phases, something you would have to emulate.  The STM32 also has a digital filter to skip noise on the line, a problem if you have single-ended phase inputs on a long cable.  I suspect your best solution is to go with a set of small M0 type parts to decode the QEIs, tying all the single chip M0s together with I2C or SPI.  That gives you a minimal pin count and an unlimited number of QEI interfaces.

How do you determine you are losing data?  At what point do you look at the timer count?  The best time to check count is at either the phase A or phase B interrupt, that way you don't get the edge oscillation.

  Jack Peacock

emalund
Associate III
Posted on April 30, 2013 at 17:01

Erik, I'm not sure to see what you meant there.

you can not decode quadrature encoded by your quadrature encoder from Bourns with another encoder, to decode quadrature you need a quadrature decoder

 

 

Erik
frankfrank956
Associate III
Posted on April 30, 2013 at 18:11

Is it out of the question to use external counter devices line the LSI7366?

http://www.lsicsi.com/pdfs/LS7366.pdf

You would still need 2+2n lines. Or they do a four axis decoder/counter.

Better yet, how about a separate, 48-pin STM32 device that is dedicated to just polling the encoders at high speed. Then use a SPI or I2C interface to the master processor?

How fast will the data be arriving anyway? I read two quadrature encoders with pulse rates in the tens of kHz each with no problems on an STM32F4

michaelmichael9137
Associate II
Posted on May 02, 2013 at 15:07

Ok thanks everyone.

First of all, I think my second problem is solved (data loss). I still need a way to handle 9 encoders without using 18 GPIO Pins though.

So you globally recommend to use external counters.

Clive : I think that smart encoders will be too expensive for my application being a low cost commercialized product.

Jack, what do you mean by ''M0 type parts?'', sounds exactly like what I need.

Peter, I found this  : 

http://ww1.microchip.com/downloads/en/DeviceDoc/20090C.pdf

to increase the number of GPIOs, which ables me to avoid using a second STM32, but it seems too complicated and slow. I can't afford adding a second micro controller in this project.

Thanks again for your advices.

jpeacock2399
Associate II
Posted on May 02, 2013 at 15:53

M0 controllers are smaller versions of the M3.  But your choice of LSI7366 counters in QEI mode is simpler.  Looks like the LSI7366 supports quadrature inputs and handles the edge cases.  Just conenct them all together on an SPI bus.

  Jack Peacock