How to init a counter for QEI mode?

The official pyboard running MicroPython.
This is the reference design and main target board for MicroPython.
You can buy one at the store.
Target audience: Users with a pyboard.
Post Reply
User avatar
dbc
Posts: 89
Joined: Fri Aug 28, 2015 11:02 pm
Location: Sunnyvale, CA

How to init a counter for QEI mode?

Post by dbc » Fri Sep 04, 2015 12:59 am

Just tried a quick experiment to set up a QEI interface, and the "obvious" thing didn't work for me. After reading the code in stmhal/timer.c, it isn't clear to me how initializing the counter for QEI is supposed to work. (I admit that I've used other brands before, not ST parts, so I'm still climbing that learning curve with respect to the bare metal.)

The Timer object seems to want to be initialized either with a frequency or a prescaler/divisor, which then starts it running as a timer. So, for the QEI modes, isn't it necessary to init the counter without setting either a frequency or prescaler/divisor? But with a bare call to pyb.Timer(<n>), is the timer correctly initialized for encoder mode?

The following code prints zeroes, so the counter isn't moving for me:

Code: Select all

import pyb
from pyb import Timer
from time import sleep

tim = pyb.Timer(8)
c1 = pyb.Pin('Y1',pyb.Pin.IN)
c2 = pyb.Pin('Y2',pyb.Pin.IN)
tim.channel(1,Timer.ENC_AB)
while True:
    print(tim.counter())
    sleep(1)
Also, the compiler complains if the channel number isn't given on the tim.channel() call, even though the value is ignored.
Also tried with:

Code: Select all

tim.channel(1,Timer.ENC_AB, pin=c1)

-dave

User avatar
dhylands
Posts: 3351
Joined: Mon Jan 06, 2014 6:08 pm
Location: Peachland, BC, Canada
Contact:

Re: How to init a counter for QEI mode?

Post by dhylands » Fri Sep 04, 2015 1:58 am

Here's an example I coded up when I was writing the encoder support:
https://github.com/dhylands/upy-example ... ncoder2.py

and another example where I used the pyboard to generate a quadrature output (and looped that back to decode)
https://github.com/dhylands/upy-example ... ncoder3.py

QEI is only available on channels 1/2 of a timer (HW limitation).

The period portion of the timer initialization is used, but the prescalar is ignored. So it doesn't make sense to initialize the timer using freq=
When you initialize channel 1, it implicitly initializes channel 2.

The timer API only has support for initializing one pin, so you need to setup one or both pins to the appropriate alternate function when using QEI.

User avatar
dbc
Posts: 89
Joined: Fri Aug 28, 2015 11:02 pm
Location: Sunnyvale, CA

Re: How to init a counter for QEI mode?

Post by dbc » Fri Sep 04, 2015 9:06 pm

Thanks for the examples! We have an encoder running now. I'll work up an update to the documentation and submit a pull request.

jgui
Posts: 3
Joined: Thu Nov 10, 2016 5:06 pm

Re: How to init a counter for QEI mode?

Post by jgui » Mon Jul 16, 2018 10:25 pm

dhylands wrote:
Fri Sep 04, 2015 1:58 am
Here's an example I coded up when I was writing the encoder support:
https://github.com/dhylands/upy-example ... ncoder2.py

and another example where I used the pyboard to generate a quadrature output (and looped that back to decode)
https://github.com/dhylands/upy-example ... ncoder3.py

QEI is only available on channels 1/2 of a timer (HW limitation).

The period portion of the timer initialization is used, but the prescalar is ignored. So it doesn't make sense to initialize the timer using freq=
When you initialize channel 1, it implicitly initializes channel 2.

The timer API only has support for initializing one pin, so you need to setup one or both pins to the appropriate alternate function when using QEI.

I recently use the pyboard to interface with a quadrature encoder and start from your examples, many thanks!

Despite that I struggle some time before getting expected result. What I found is that prescaler must be set to 0 for correct counting.

I initially start from encoder3.py in which prescaler is set to 1 but I do not realize that. Result was a counting that looks like ENC.A (or ENC.B) when in mode EN_AB. More critical, when oscillating around a single edge, counter was continuously incrementing instead of oscillating between X and X+1!

So prescaler is not ignored as written in encoder2.py and must be set to 0 to get a divisor of 1 (ie no prescaler).

When set to 0 everything is fine, counter value changes as described in the documentation.
Also comment in encoder2.py is not true when prescaler=0:
# ENC_AB will increment/decrement on the rising edge of either the A channel or the B
# channel.
Counter value changes on any change of CH1 or CH2 (in mode ENC_AB).

Post Reply