cancel
Showing results for 
Search instead for 
Did you mean: 

Quadrature encoders roll over management

demond
Associate
Posted on November 19, 2013 at 02:25

Hi,

I am currently developping a firmware programmed into a STM32F407VG microcontroller.

The firmware has the following tasks:

- Reading motor positions (5 axes: 3 with quadratures/indexes and 2 with steps/directions),

- Trig a laser pulse at a specific motor positions (synchronized with only 1 axis),

- Send a PWM signal to the laser to keep it in a simmering state,

- Trig a scanner laser line to read a scanner profiles at specific motor positions (synchronized with 2 axes),

- Read a bunch of digital inputs,

- Write a few digital outputs,

- Read the Board temperature,

- Read 2 analog inputs, and

- Eventually control the motors (phase 2 of the project).

Communication is done via USB FS. Eventually, I'll require I2C communication (surprisingly, I still have the secondary I2C available for that purpose).

As you can see, I'm kinda low on available ressources. All the timers are used, 75% of the embedded RAM is used, etc.

I've been able to complete most of the work (and it seems to be working). My only concern right now is the way I extend the 16bits timers to 32bits to track the positions (a full rotation is 160000 encoder pulses and the resolution on the translation axes is 2000 encoder pulses per mm).

I have read in the reference manual (RM0090 - DM00031020.pdf) that when configured in encoder mode, the direction bit (bit 4) of the control register 1 (TIMx_CR1:DIR) is set as read only. I was hoping that the direction bit was updated as per the timer counter increment/decrement operations, i.e.: can I use it to determine the roll over direction of the counter ?

bool isCountingUpward = TIM2->CR1 & 0x0010 ? false : true;

Does it get updated by the phase A/B shifts ?

How reliable is the solution presented in this thread:

[DEAD LINK /public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Flat.aspx?RootFolder=/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/32bit%20quadrature%20encoder&FolderCTID=0x01200200770978C69A1141439FE559EB459D7580009C4E14902C3CDE46A77F0FFD06506F5B&TopicsView=https://my.st.com/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/AllItems.aspx?View%3D%7bF47A9ED8-E726-42BE-ACED-732F13B66581%7d%26FilterField1%3DLinkDiscussionTitle%26FilterValue1%3D32bit%2520quadrature%2520encoder&currentviews=1132]https://my.st.com/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Flat.aspx?RootFolder=%2fpublic%2fSTe2ecommunities%2fmcu%2fLists%2fcortex_mx_stm32%2f32bit%20quadrature%20encoder&FolderCTID=0x01200200770978C69A1141439FE559EB459D7580009C4E14902C3CDE46A77F0FFD06506F5B&TopicsView=https%3A%2F%2Fmy%2Est%2Ecom%2Fpublic%2FSTe2ecommunities%2Fmcu%2FLists%2Fcortex_mx_stm32%2FAllItems%2Easpx%3FView%3D%7BF47A9ED8-E726-42BE-ACED-732F13B66581%7D%26FilterField1%3DLinkDiscussionTitle%26FilterValue1%3D32bit%2520quadrature%2520encoder&currentviews=1132

#timer-encoder-qei
8 REPLIES 8
kobus
Associate II
Posted on November 19, 2013 at 13:34

In my experience using an overflow interrupt to scale up an encoder is not reliable, especially when you have high resolution encoders: it happens from time to time that the encoder value will change sign in the instant you enter the interrupt, causing the system to increment the upper word when it should have decremented etc. This is especially true if the encoder is supposed to be stalled at 0, like a servo motor commanded to go to encoder position 0.  

The best approach I have found is to do it manually. this is my procedure:

1: Ensure that the control loop that reads the encoder value is run often, (i.e. that if your encoder is rotating at full speed, the encoder value is still read at least 10-20 times between overflows. For my servo motor application a 1ms loop interval was sufficient. 

2: keep track of the last read encoder value.

3: divide the current and last encoder value into quadrants (the most significant 2 bits). i.e. pos_now &= 0xC000; pos_last &= 0xC000;

4: check to see if the encoder has moved from quadrant 0 to quadrant 3 or 3 to 0 in the last step:

if(pos_now == 0 && pos_last == 0xC000) upper_word++;

if(pos_now == 0

xC000

&& pos_last == 0)

 upper_word--;

this is why I say the encoder read loop needs to be run often; you need to be sure that the value is read often enough that it is impossible to go from quadrant 0->1->2->3 in between reads.

It should also be possible to put this logic in another timer interrupt that runs at say 10kHz. that way you have an encoder value which is always up to date. 

Posted on November 19, 2013 at 13:41

I'd certainly look at committing the 32-bit counters to encoder tasks, for timing tasks the combination of 16-bit prescaler and period provide for two 16-bit factors, which while not ideal for covering all 32-bit combinations and frequencies, is certainly more controllable.

The timers, and integer dividers, are in my opinion one of the limiting factors in the STM32's utility.
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 November 19, 2013 at 15:37

anyone know where this stupidity originated

these threads are not discussing a quadrature encoder, they are discussing a quadrature <b>de</b>coder

Erik
Amel NASRI
ST Employee
Posted on November 20, 2013 at 10:34

anyone know where this stupidity originated

 

 

No one can learn without making mistakes, don't understand why such comment...

-Mayla-

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

frankmeyer9
Associate II
Posted on November 20, 2013 at 10:52

No one can learn without making mistakes, don't understand why such comment...

 

Erik is known for not pussyfooting around those points. And basically I need to agree with him.

If it was a mistake with the F1 devices, why, then, was it repeated for the F2, L1, F0, F4 and F3 devices ?

Copy/Paste of peripheral IP blocks from 8/16 bit designs to 32 bit designs might speed up time-to-market, but seen as an obstacle by some customers.

jpeacock2399
Associate II
Posted on November 20, 2013 at 15:54

If you want to argue semantics then the discussion is about the quadrature ENCODER interface, the timers which connect to the quadrature ENCODER on the motor.  Shortening it to the more colloquial quad encoder is not a stupid idea...there's no ambiguity about the subject.  It's clear the reference is to the timer QEI interface.

  Jack Peacock
emalund
Associate III
Posted on November 20, 2013 at 16:15

about the quadrature ENCODER interface, which is a quadrature decoder.

Erik

Posted on November 20, 2013 at 17:26

Copy/Paste of peripheral IP blocks from 8/16 bit designs to 32 bit designs might speed up time-to-market, but seen as an obstacle by some customers.

I can certainly understand some of the choices were driven by silicon area, but the designs seems to be lacking some clarity and ingenuity at the system and peripheral level. The clocking flexibility is woeful, even in areas where different clock domains are handled.

The bulk of the timers should have been 32-bit from the outset, and slave timers should have visibility to the control signals the master can see. Using 16-bit counters for a relatively slow speed encoder interface is pretty shameful in my opinion. The TIM units are far too complicated and limiting (kitchen sink approach), it would have been far more efficient to have implemented smaller functional units that addressed a specific task and did it properly.

The STM32F429I-DISCO illustrates some very poorly executed pin muxing/escape strategy (no SDIO free), and the EVAL boards use of IO Expanders suggests a lack of planning at the silicon level. Can one even use the USB interface with the CPU clocking at 180 MHz? Who let that happen?

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