0

I have a Pololu 4x encoder and am trying to write some code to make it work on my Nano 33 BLE. (Interestingly enough, the issue preventing some pre-existing libraries from working for me is the same issue that I'm about to describe here...)

When I turn the motor shaft clockwise, these are the signals that I get (first bit in each pair is channel A, second bit channel B):

11 -> 10 -> 11 -> 10 -> 11 -> 10

Note how channel A's value never changes, and B's value toggles back and forth.

Likewise, for the counterclockwise direction:

01 -> 11 -> 01 -> 11 -> 01 -> 11

This is of course wrong, as the channels' values should be something like 00 -> 10 -> 11 -> 01 -> 00 as the shaft turns. As a matter of fact, that is exactly what I get when I run the exact same code on a regular Arduino Nano.

Does anyone know what's going on? Here's my code. AFAIK I'm not using interrupts incorrectly or anything, at least for the regular Nano.

#define PIN_A 2
#define PIN_B 3

volatile int val = 0;
volatile bool newVal = true;

void encoder() {
  int a = digitalRead(PIN_A);
  int b = digitalRead(PIN_B);
  val = ((a << 1) | b);
  newVal = true;
}

void setup() {
  Serial.begin(57600);

  pinMode(PIN_A, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(PIN_A), encoder, CHANGE);

  pinMode(PIN_B, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(PIN_B), encoder, CHANGE);
}

void loop() {
  if (newVal) {
    Serial.print(bool(val & 0b10));
    Serial.print(bool(val & 0b01));
    Serial.println();
    newVal = false;
  }
}

EDIT: After taking a look at the following diagram, it appears that the erroneous encoder patterns match those in which only rising edges are detected. So for some reason, attachInterrupt() is acting as if the CHANGE argument were RISING instead for the Nano BLE.

enter image description here

  • 2
    Probably not the source of your issue, but change val from a volatile int to a volatile byte. You only need one byte and with int you're technically doing a multi-byte read of a volatile variable with all that entails. – Delta_G Apr 26 at 4:27
0

Best practice would be to use a single interrupt for the encoder. BLE has a faster processor and your code is not frame-based so that just might affect it also. This code doesn't do exactly what your code did but it will use val to track position as a number. It can also be made a bit finer using CHANGE instead of RISING, but for debugging bare bones means less that can go wrong.

#define PIN_A 2
#define PIN_B 3

volatile int val = 0;
int oldVal;
//volatile bool newVal = true;

void encoder() {
  if(digitalRead(PIN_B)) ++val;
  else --val;
}

void setup() {
  Serial.begin(57600);

  pinMode(PIN_A, INPUT_PULLUP);
  pinMode(PIN_B, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(PIN_A), encoder, RISING);
}

void loop() {
  if (val != oldVal) {
    oldVal = val;
    Serial.println(oldVal);
  }
  delay(500);
}
| improve this answer | |
  • Welcome to Arduino:SE. Please don't post multiple answers to the same question. Just edit the information into your original answer. – sempaiscuba Apr 26 at 16:20
  • Please evaluate answers as answers without bias for who posted them. – Abel Apr 26 at 16:37
  • 1
    I'm not bothered by who posts the answers, but SE is a Q&A site, rather than the forums you might be used to. There is rarely any need for anyone to post more than one answer to a given question. You might find it helpful to review the site tour and Help Centre and, in particular, How do I write a good answer?. – sempaiscuba Apr 26 at 16:44
0

So it turns out the cause of the issue was that attachInterrupt()'s implementation in the nRF528x Mbed core does not properly support rising/falling edge detection as required for mode CHANGE. I've opened a pull request implementing the changes required and tested them with my encoder, and I can confirm that everything works properly now.

If you'd like to test the updated core yourself, you can follow the installation instructions from the repo's README or from this very well-written forum post.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.