EncoderTool wrong value on first anti-clockwise adjustment after power up

rvh

Well-known member
I'm using EncoderTool.h (version 3.2.0 + Teensyduino 1.59) on T4.1 with a Bourns 24 detent encoder (PEC11R-4215F-S0024) and getting an error for the very first anti-clockwise adjustment after power up. The error arises between the initial and next (anti-clockwise) detent, as soon as the encoder is moved even the slightest. But it only occurs once, and only if the first adjustment is anti-clockwise, and not for clockwiise adjustments.

The following standard encoder test code reproduces this error for me.
Code:
#include <EncoderTool.h>
using namespace EncoderTool;
Encoder eA0;

void setup() {
  eA0.begin(17, 16);   
  eA0.setValue(0);
}

void loop() {
    if (eA0.valueChanged()  )
    {     
      int delta = eA0.getValue();
      Serial.println(delta);   
      eA0.setValue(0);       
    }
    delay(10);
}

When working correctly, this prints 1 for slow clockwise adjustments, and -1 for anti-clockwise adjusments. But more often than not, the first anti-clockwise adjustment after power up prints
1
-1
rather than just -1.

After the first adjustment, or if the first adjustment is clockwise, everything works as it should.

Seems to be a bug?
 
Last edited:
Looks like it doesn't read the pinlevels at startup correctly. How did you connect the encoder?
 
I tested your code with a directly connected encoder (common GND) without any additional stuff. It works without issue here.
 
>Looks like it doesn't read the pinlevels at startup correctly. How did you connect the encoder?
>I tested your code with a directly connected encoder (common GND) without any additional stuff. It works without issue here.

My encoder is directly connected too, with A/B to pins 17/16 on T4.1 and the common center pin to ground.

But please make sure you are only testing the output directly after a power up, with an single anti-clockwise click. That's the only case where the output is wrong. After that single click, or if you do a clockwise click it works just fine, and you need to do another power cycle to see the error again.

For debugging purposes, I also tried full countmode rather than quarter mode using eA0.setCountMode(CountMode::full), and the same issue manifests and gives the following 4 output values in response to the first single anticlockwise detent step after power up:
1
-1
-1
-1
Again, the first output is wrong
 
The datasheet is a bit unclear, can it be that this encoder has only half a quadrature period per detent? You can try by setting it to CountMode::full and see how much the count value increases if you rotate the encoder by one detent.

I tested by resetting between trials. Going to do powercycling now...
 
OK, I can reproduce the issue with powercycling.
During the `begin()` function the library sets the pinmode of the input pins to the required value and immediately after that reads in the starting values of the A/B pins. For some reason I don't really understand, it needs some time between setting the pinMode and reading the value after power up. Placing a 1µs delay between setting the pinMode and reading in the start values fixes it for me. Can you give that a try?

Just add
Code:
51  pinMode(A.pin, inputMode);
52  pinMode(B.pin, inputMode);
53  delayMicroseconds(1);  <------ add this in line 53

in `Encoder.h`
 
The datasheet is a bit unclear, can it be that this encoder has only half a quadrature period per detent? You can try by setting it to CountMode::full and see how much the count value increases if you rotate the encoder by one detent.

I tested by resetting between trials. Going to do powercycling now...
No, as I showed above the encoder gives 4 outputs per detent. Also, it works exactly as expected apart from that very specific first anticlockwise detent click after power up. Seems more like some sort of initialization issue to me.
 
OK, I can reproduce the issue with powercycling.
During the `begin()` function the library sets the pinmode of the input pins to the required value and immediately after that reads in the starting values of the A/B pins. For some reason I don't really understand, it needs some time between setting the pinMode and reading the value after power up. Placing a 1µs delay between setting the pinMode and reading in the start values fixes it for me. Can you give that a try?

Just add
Code:
51  pinMode(A.pin, inputMode);
52  pinMode(B.pin, inputMode);
53  delayMicroseconds(1);  <------ add this in line 53

in `Encoder.h`
Do you mean in EncoderTool.h? I'm having a bit of trouble locating where that lives (but see the stock encoder.h lib no problems). Will report back when I can find it!

...OK I see you probably mean encoder.h in the src/single directory?
 
Tested now with the 1us delay added after setting pinmodes in encoder.h, and can confirm it fixes the issue for me too.
Thanks very much, it's greatly appreciated.
 
Thanks for spotting it. I just published v3.2.2 on GitHub which fixes the issue. May take a few hours until the Arduino & PlO library managers detect the changed version.
 
On a somewhat related note, I find with the encoder I'm using that I don't always get changes when clicking to a next detent. Switching to full mode shows more or less than the expected 4 pulse changes. Is there a way of dealing with this in software so I can ensure single increments/decrements on each detent? I've tried gong to full mode and processing those data but haven't succeeded in a reliable solution so far. Thanks.
 
The library is pretty imune against any bouncing as long as bounces don't overlap. I.e., if your encoder bounces so badly that one switch still bounces while the other switch changes transition you might get wrong counts. The same might happen if your encoder bounces extremely fast so that interrupts overlap a lot. Do you have access to a scope or logic analyzer to measure what your pins are actually doing?

This is how a random, perfectly working encoder looks like

1713593786665.png


Zoomed in on the up-transition of B:
1713593889589.png


Did you try the polled version? It is more resilient to fast bouncing encoders.

C++:
#include <EncoderTool.h>
using namespace EncoderTool;

PolledEncoder eA0;

void setup()
{
    eA0.begin(0, 1);
}

void loop()
{
    eA0.tick();
    if (eA0.valueChanged())
    {
        Serial.println(eA0.getValue());
    }
}
 
Thanks for the follow up. It turned out that the particular encoder I was testing was worse than most others that I tried (of the same model). But it would be nice to have my design more immune to sample variation. I'll give the polled version a try.
 
Back
Top