You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@nuttx.apache.org by Petro Karashchenko <pe...@gmail.com> on 2022/01/13 13:19:15 UTC

Qencoder position value range

Hi,

I've been working to add SAMv7 Qencoder interface and see that Qencoder
driver expects QEIOC_POSITION to be int32_t value. The issue is that SAMv7
has 16 bit timer counter interface and the SW extension to 32 bits (by
adding adding or subtracting UINT16_MAX+1 when counter matches 0xffff) does
not seems to work reliably because sometimes pulses are incremented /
decremented not by 1 by the HW.

The question that I have is whether the Qencder position is expected to
count to negative values "INT16_MIN, ..., -2, -1, 0, 1, 2, .. INT16_MAX" or
position can be in range "0 ... UINT16_MAX" or there are not strict
requirements?

Best regards,
Petro

Re: Qencoder position value range

Posted by Petro Karashchenko <pe...@gmail.com>.
Ok. So I will leave 0 ... UINT16_MAX to be returned by the driver and will
handle rollover on the application side.

Thanks!

Petro

On Thu, Jan 13, 2022, 5:15 PM Nathan Hartman <ha...@gmail.com>
wrote:

> On Thu, Jan 13, 2022 at 9:50 AM Petro Karashchenko
> <pe...@gmail.com> wrote:
> >
> > Thank you. I would appreciate that, but I think that will work only if
> > there is no complete cycle between two reads, so it is potentially a
> > possibility to get wrong position.
>
> Yes, that is correct. If you know what the application will be, you
> know the maximum speed at which pulses can be counted, then you can
> calculate the sample rate that guarantees this will not happen. For
> example a 1000 RPM motor with a 1000 line encoder x 4 (quadrature)
> sampled at 1 KHz will count approximately 66-67 counts per sample, so
> will never come close to losing complete cycles. Of course, if you
> don't know the application, then you cannot control this. The same is
> true, though, if you attempt to trigger on 0->0xffff / 0xffff->0. If
> you miss this single pulse, the count will be corrupted. So maybe it
> is better to risk missing a full cycle than to risk missing a single
> pulse.
>
> The code I mentioned is basically as follows (indentation is getting
> messed up in the email):
>
> static uint16_t Prev = 0;
> static uint16_t Curr = 0;
> static uint16_t Delta = 0;
> static int32_t Position = 0;
>
> .
> .
> .
>
> Prev = Curr;
>
> Curr = READ_QENCODER_COUNTER_HERE();
>
> Delta = Curr - Prev;
> if (Delta > 0x7fff) {
> Delta = (0 - Delta);
> Position -= (int32_t)(Delta);
> }
> else {
> Position += (int32_t)(Delta);
> }
>
> return Position;
>
> Cheers,
> Nathan
>

Re: Qencoder position value range

Posted by Nathan Hartman <ha...@gmail.com>.
On Thu, Jan 13, 2022 at 9:50 AM Petro Karashchenko
<pe...@gmail.com> wrote:
>
> Thank you. I would appreciate that, but I think that will work only if
> there is no complete cycle between two reads, so it is potentially a
> possibility to get wrong position.

Yes, that is correct. If you know what the application will be, you
know the maximum speed at which pulses can be counted, then you can
calculate the sample rate that guarantees this will not happen. For
example a 1000 RPM motor with a 1000 line encoder x 4 (quadrature)
sampled at 1 KHz will count approximately 66-67 counts per sample, so
will never come close to losing complete cycles. Of course, if you
don't know the application, then you cannot control this. The same is
true, though, if you attempt to trigger on 0->0xffff / 0xffff->0. If
you miss this single pulse, the count will be corrupted. So maybe it
is better to risk missing a full cycle than to risk missing a single
pulse.

The code I mentioned is basically as follows (indentation is getting
messed up in the email):

static uint16_t Prev = 0;
static uint16_t Curr = 0;
static uint16_t Delta = 0;
static int32_t Position = 0;

.
.
.

Prev = Curr;

Curr = READ_QENCODER_COUNTER_HERE();

Delta = Curr - Prev;
if (Delta > 0x7fff) {
Delta = (0 - Delta);
Position -= (int32_t)(Delta);
}
else {
Position += (int32_t)(Delta);
}

return Position;

Cheers,
Nathan

Re: Qencoder position value range

Posted by Petro Karashchenko <pe...@gmail.com>.
Thank you. I would appreciate that, but I think that will work only if
there is no complete cycle between two reads, so it is potentially a
possibility to get wrong position.

I will try experiment more with timer counter interrupts to see if 0 ->
0xFFFF and 0xFFFF -> 0 situations.

I will appreciate if you can share your code so I can take it as a
reference.

Best regards,
Petro

On Thu, Jan 13, 2022, 4:26 PM Nathan Hartman <ha...@gmail.com>
wrote:

> On Thu, Jan 13, 2022 at 8:19 AM Petro Karashchenko <
> petro.karashchenko@gmail.com> wrote:
>
> > Hi,
> >
> > I've been working to add SAMv7 Qencoder interface and see that Qencoder
> > driver expects QEIOC_POSITION to be int32_t value. The issue is that
> SAMv7
> > has 16 bit timer counter interface and the SW extension to 32 bits (by
> > adding adding or subtracting UINT16_MAX+1 when counter matches 0xffff)
> does
> > not seems to work reliably because sometimes pulses are incremented /
> > decremented not by 1 by the HW.
> >
> > The question that I have is whether the Qencder position is expected to
> > count to negative values "INT16_MIN, ..., -2, -1, 0, 1, 2, .. INT16_MAX"
> or
> > position can be in range "0 ... UINT16_MAX" or there are not strict
> > requirements?
> >
> > Best regards,
> > Petro
>
>
>
> Correct; you can't rely on that.
>
> >
> I don't know at the moment whether the position is expected to be signed or
> unsigned, but I have code somewhere to extend precision from 16 bit to 32
> bit. If I remember correctly it always saves the previous reading. Each
> time it samples the encoder it subtracts the old from the new. If > 0x7fff
> it subtracts the complement, otherwise it adds the value, to a 32-bit
> variable, which is used as the counter. Let me know if you need me to find
> the code.
>
> Hope this helps,
> Nathan
>

Re: Qencoder position value range

Posted by Nathan Hartman <ha...@gmail.com>.
On Thu, Jan 13, 2022 at 8:19 AM Petro Karashchenko <
petro.karashchenko@gmail.com> wrote:

> Hi,
>
> I've been working to add SAMv7 Qencoder interface and see that Qencoder
> driver expects QEIOC_POSITION to be int32_t value. The issue is that SAMv7
> has 16 bit timer counter interface and the SW extension to 32 bits (by
> adding adding or subtracting UINT16_MAX+1 when counter matches 0xffff) does
> not seems to work reliably because sometimes pulses are incremented /
> decremented not by 1 by the HW.
>
> The question that I have is whether the Qencder position is expected to
> count to negative values "INT16_MIN, ..., -2, -1, 0, 1, 2, .. INT16_MAX" or
> position can be in range "0 ... UINT16_MAX" or there are not strict
> requirements?
>
> Best regards,
> Petro



Correct; you can't rely on that.

>
I don't know at the moment whether the position is expected to be signed or
unsigned, but I have code somewhere to extend precision from 16 bit to 32
bit. If I remember correctly it always saves the previous reading. Each
time it samples the encoder it subtracts the old from the new. If > 0x7fff
it subtracts the complement, otherwise it adds the value, to a 32-bit
variable, which is used as the counter. Let me know if you need me to find
the code.

Hope this helps,
Nathan