Adafruit motor shield example doesn't update RPM

I'm trying to drive an N20 motor with encoder, using the Adafruit motor shield V3.
When running the example code that comes with the package, encoderMotorRPM, the motor does turn, but the serial only prints the initial messages followed by Direction: forward @ 0 RPM repeatedly, regardless the actual direction and speed of the motor.

The code below is directly copied from the example. The only modification I made is commenting out all the lines pertaining to the OLED screen, since I don't have one.

I've never worked with encoder motors or the attachInterrupt() command, so I don't know where to start troubleshooting this code.

#include <Wire.h>
#include <Adafruit_MotorShield.h>
// #include <Adafruit_SSD1306.h>

// Connect to the two encoder outputs!
#define ENCODER_A   12
#define ENCODER_B   11

// These let us convert ticks-to-RPM
#define GEARING     20
#define ENCODERMULT 12

// Create the motor shield object with the default I2C address
Adafruit_MotorShield AFMS = Adafruit_MotorShield();
// And connect a DC motor to port M1
Adafruit_DCMotor *myMotor = AFMS.getMotor(1);
// We'll display the speed/direction on the OLED
// Adafruit_SSD1306 display = Adafruit_SSD1306(128, 32, &Wire);

volatile float RPM = 0;
volatile uint32_t lastA = 0;
volatile bool motordir = FORWARD;

void interruptA() {
  motordir = digitalRead(ENCODER_B);

  digitalWrite(LED_BUILTIN, HIGH);
  uint32_t currA = micros();
  if (lastA < currA) {
    // did not wrap around
    float rev = currA - lastA;  // us
    rev = 1.0 / rev;            // rev per us
    rev *= 1000000;             // rev per sec
    rev *= 60;                  // rev per min
    rev /= GEARING;             // account for gear ratio
    rev /= ENCODERMULT;         // account for multiple ticks per rotation
    RPM = rev;
  }
  lastA = currA;
  digitalWrite(LED_BUILTIN, LOW);
}

void setup() {
  Serial.begin(9600);           // set up Serial library at 9600 bps
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);

  pinMode(ENCODER_B, INPUT_PULLUP);
  pinMode(ENCODER_A, INPUT_PULLUP);
  attachInterrupt(ENCODER_A, interruptA, RISING);

  delay(100);

  // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  // if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3C for 128x32
  //   Serial.println(F("SSD1306 allocation failed"));
  //   for(;;); // Don't proceed, loop forever
  // }
  // display.display();
  // display.setTextSize(2);
  // display.setTextColor(WHITE);

  //while (!Serial) delay(1);

  Serial.println("MMMMotor party!");
  if (!AFMS.begin()) {         // create with the default frequency 1.6KHz
  // if (!AFMS.begin(1000)) {  // OR with a different frequency, say 1KHz
    Serial.println("Could not find Motor Shield. Check wiring.");
    while (1);
  }
  Serial.println("Motor Shield found.");  Serial.println("Begun");
  // turn on motor M1
  myMotor->setSpeed(0);
}

void printRPM() {
    // display.clearDisplay();
    // display.setCursor(0,0);

    Serial.print("Direction: ");
    if (motordir) {
      // display.println("Forward");
      Serial.println("forward @ ");
    } else {
      // display.println("Backward");
      Serial.println("backward @ ");
    }
    // display.print((int)RPM); display.println(" RPM");
    Serial.print((int)RPM); Serial.println(" RPM");
    // display.display();
}

int i;
void loop() {
  delay(50);
  myMotor->run(FORWARD);
  for (i=0; i<255; i++) {
    myMotor->setSpeed(i);
    delay(20);
    printRPM();
  }

  for (i=255; i!=0; i--) {
    myMotor->setSpeed(i);
    delay(20);
    printRPM();
  }

  myMotor->run(BACKWARD);
  for (i=0; i<255; i++) {
    myMotor->setSpeed(i);
    delay(20);
    printRPM();
  }

  for (i=255; i!=0; i--) {
    myMotor->setSpeed(i);
    delay(20);
    printRPM();
  }
}

Schematic:

Hi there! I'm currently working on this for my own project as I had the same issues with the example code. I will update as I go along, but here is what I have found so far.

I am using the Adafruit Motor Shield V3 with an Arduino UNO R3 and a N20 (6V, 1:50 Gear Ratio). My Arduino and Motor Shield are powered by two independent sources.

The Arduino UNO (at least the one I'm using) only supports interrupts for pins 2 and 3 (you can check your Arduino here: https://docs.arduino.cc/language-reference/en/functions/external-interrupts/attachInterrupt/). I have my motor wired as follows:
Black wire to Arduino 3V
Blue wire to Arduino ground
Green wire to Arduino pin 3

I have this code written:

#include <Adafruit_MotorShield.h>

Adafruit_MotorShield AFMS = Adafruit_MotorShield();
Adafruit_DCMotor *leftMotor = AFMS.getMotor(1);

#define ENCODER_A_L 3
#define TICKS_TO_RPM 1

int i = 0;

void interruptA_L() {
  Serial.println(i);
  ++i;
}

void setup() {
  Serial.begin(9600);
  Serial.println("Start.");

  if (!AFMS.begin()) {
    Serial.println("Motor Shield not found.");
    while (1);
  }
  Serial.println("Motor Shield found.");

  // Turn motor off
  leftMotor->setSpeed(0);
  leftMotor->run(RELEASE);

  pinMode(ENCODER_A_L, INPUT_PULLUP);
  pinMode(ENCODER_B_L, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(ENCODER_A_L), interruptA_L, RISING);
}

void loop() {
}

The code will count the interrupts of the encoder as you manually turn the motor and show them on the Serial Monitor.

I will be working on this, so I can update how I get the RPM sometime in the next few days.

you should not use Serial.print() inside an interrupt…

That is correct, I will eventually remove it. It’s currently there for debugging purposes.

See below for my completed code. It's not optimal, but it is sufficient for my purposes.

My components are:
Arduino UNO R3
Adafruit Motor Shield V3
N20 DC Motor (6V with 1:50 Gear Ratio)

I'm powering the motor shield with 5 AA batteries. The Arduino is powered by USB from my laptop.

The wiring for the DC motor is as follows:
Red wire - M1 Power
White wire - M1 Ground
Black wire - Arduino 3V
Blue wire - Arduino Ground
Yellow wire - Arduino Pin 3

Code:

#include <Adafruit_MotorShield.h>

// create motor shield object and dc motor object
Adafruit_MotorShield AFMS = Adafruit_MotorShield();
Adafruit_DCMotor *leftMotor = AFMS.getMotor(1);

#define ENCODER_L 3 // encoder wire on pin 3
#define TICKS_PER_REV 350 // number of ticks per revolution

int ticks = 0; // counts ticks from last interval
int speed = 0; // speed of motor, from 0 to 255
bool faster = true; // denotes whether motor is accelerating or decelerating

// counts ticks
void interrupt_L() {
  ++ticks;
}

void setup() {
  // start serial
  Serial.begin(9600);
  Serial.println("Start.");  

  // check if motor shield is connected
  if (!AFMS.begin()) {
    Serial.println("Motor Shield not found.");
    while (1);
  }
  Serial.println("Motor Shield found.");
  
  // set encoder pin for left motor
  pinMode(ENCODER_L, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(ENCODER_L), interrupt_L, RISING);
}

void loop() {
  // every 50 ms, use number of ticks to determine rev/sec
  delay(50);
  Serial.print("Revolutions per second: ");
  Serial.println(ticks/(TICKS_PER_REV * 0.05));
  ticks = 0;

  // increase and decrease motor speed
  if (faster) {
    speed += 1;
    if (speed >= 250) {
    faster = false;
    }
  }
  else {
    speed -= 1;
    if (speed <= 0) {
    faster = true;
    }
  }

  // run motor
  leftMotor->setSpeed(speed);
  leftMotor->run(FORWARD);
}

The program counts the number of encoder ticks in a 50 millisecond interval and uses that to estimate the angular velocity. The resolution is high enough for my project, but there are other ways to calculate the angular velocity (e.g. measure time between two ticks and use that to find the velocity). There's only two pins that support interrupts on my Arduino, and since I need to use two motors, I am reserving Pin 2 for my other motor. Unfortunately this means I cannot determine direction using the second encoder wire (green wire), as I have nowhere to wire it to, so I can't supply that code for you.

Let me know if you have any questions/comments/suggestions.

Could you give a link to this shield? I haven't run across a V3 motor shield from Adafruit, just the one from Arduino.

I just checked my order history, and it seems as if I ordered the V2 kit (They shipped me a V3? I couldn't find a link where the V3 was available). Here's the link to what I ordered: Adafruit Motor/Stepper/Servo Shield for Arduino v2 Kit [v2.3] : ID 1438 : Adafruit Industries, Unique & fun DIY electronics and kits

So far, it's been able to do everything I want it to do, so would recommend!

Here's a picture of what I was sent (ignore the questionable soldering, that's my doing):

Interesting! Thank you for that. I kept hearing about a v3 motor shield from Adafruit but this is the first time I've actually seen one. I see that their v2.3 page has been updated with pictures of the v3, but not the tutorial (which also still has a v2.2 schematic).

Why? Poor solder joints, such as the several rather obvious examples in the posted photo, very often lead to malfunctions.

Capture

Fix them. Adafruit has excellent soldering tutorials.

With the Arduino Uno, you can use pin change interrupts. It's quite simple if you use a library.

There are two I would recommend, and they are both available through the library manager.

There is Nico Hood's library PinChangeInterrupt which uses very similar syntax to the external interrupt code you are with attachInterrupt() replaced with attachPCINT()

There is also GreyGnome's library EnableInterrupt.

To answer your why: I still need more practice. I'm working on getting better, but that's the level I'm at now. Thank you for your suggestion of watching soldering videos; I have found them helpful in the past.

Great info! Thank you so much for sharing and for all of the detailed information; I hadn't realized this was an option. I will definitely look into the libraries you linked!

You should pratice before you perform... or bad things happen. I would put the project on hold, read what happens during soldering and practice good soldering techniques.

Investigate the whys and hows of volatile.

Thanks for the warning! I'll double back and give it another shot before I move on. Unfortunately, I have a deadline that won't give me too much time to practice, but I will do my best to fix what I have now and be better in the future.

Thanks for the tip! It seems as if I do need to to declare the variable as volatile. To confirm the reasoning behind your suggestion, the motivation to use volatile is because the interrupt is implemented as a concurrent thread, executing in parallel with the code run in the loop, and the compiler might optimize it so that the interrupt only modifies the variable in the register, so if the main code calls the variable, it may use an older, un-updated version of the variable stored in the memory? By using volatile, we remove this optimization and force the assembly instructions to always load and store the variable directly from and into memory every time the variable is used?