Why does adding a servo motor to pin 10 affect PWM on pin 45?

This is a perplexing problem to me. I am new to Arduinos.

I have an Arduino Mega with an Adafruit motor shield (Adafruit Motor/Stepper/Servo Shield for Arduino v2 Kit [v2.3] : ID 1438 : $19.95 : Adafruit Industries, Unique & fun DIY electronics and kits) on it.

For now, I want two devices connected to it -

  1. A servo motor that I want to position in the usual fashion, to some point between 0 and 180 degrees. It has its own power supply.

  2. A vibratory motor (in a dispensing device) that functions at different speeds, based on the voltage (0 - 3 V) applied to it. It has its own 5 V power supply, separate from the one for the servo, but 5V will (eventually) cook it, so I'm using PWM via analogWrite() to reduce that to a safe level and to exert fine control how much voltage in the 0-3V range is applied to it.

Both devices are both controlled by serial commands received from the computer. It's a simple one-way communication protocol:

If I send ">S123<" to the Arduino, it puts the servo at 123 deg.

If I send ">V255<" to the Arduino, it calls analogWrite to put up 5V to the drain pin, and the vibratory motor sees a 0V potential and is off.

If I send ">V102<" to the Arduino, it calls analogWrite to put up 2V to the drain pin (102 / 255 * 5), and the vibratory motor sees a 3V potential and runs at full speed. ">V153"< gets it to 2V and a slower speed, etc.

Both features work separately. The servo moves as expected. The potential measured between the vibratory motor power supply (+5V) and the drain pin (#45) is also exactly as expected.

The problem is when I have both features in the same program. In this case, the servo still works just fine, but no matter what value analogWrite( 45, [0-254] ) calls, the measured potential is always 5 V, and analogWrite( 45, 255 ) cuts the potential to 0 V.

It appears to me that something about setting up and using the servo breaks the PWM on pin 45.

The following is Arduino code that functions properly to set the voltage to the vibrating dispensing motor.

After that is a labeled photo to illustrate the part arrangement and wiring, on the off chance it's helpful and exposes a mistake I'm making there.

If I uncomment out the lines related to the servo ... the servo functions properly, but now the voltage to the vibrating dispenser motor appears to be an ALL OR NONE result. ">V255<" results in 0V but any number from 0 - 254 results in 5V.

What gives?

Thank you.

#include <Wire.h>
#include <Adafruit_MotorShield.h>
#include "utility/Adafruit_PWMServoDriver.h"
#include <Servo.h> 
#include <ctype.h>

//Adafruit_MotorShield AFMS = Adafruit_MotorShield(); 
//Adafruit_StepperMotor *myStepper = AFMS.getStepper(200, 2);
//Adafruit_DCMotor *myMotor = AFMS.getMotor(1);
//Servo servo1;

void setup() {
  pinMode (45, OUTPUT);
  analogWrite( 45, 255 ); // ensure V motor is OFF at startup
  
  Serial.begin(115200);
//  AFMS.begin();  
//  servo1.attach(10);
}

void loop() {
  char c_start, c_end;
  char command_name, command_data[4];
  int command_data_value;
  
  // read from serial port until beginning of command is received
  while( 1 ) {
    c_start = Serial.read(); delay(2);
    if( c_start == '>' ) break;
  }
  
  // get the rest of the command in format >CDDD<
  command_name = Serial.read(); delay(2);   
  command_data[0] = Serial.read(); delay(2);
  command_data[1] = Serial.read(); delay(2);
  command_data[2] = Serial.read(); delay(2);
  command_data[3] = '\0';
  c_end = Serial.read(); delay(2);

  // is this command formatted properly?
  if( (c_start == '>') && (c_end == '<') &&
      isalpha(command_name) &&
      isdigit(command_data[0]) &&
      isdigit(command_data[1]) &&
      isdigit(command_data[2])               ) {

    command_data_value = atoi( command_data );
    
    if( command_name == 'S' ) {  // command to position servo

 //     if( command_data_value < 5 ) servo1.write( 5 );
 //     else if( command_data_value > 175 ) servo1.write( 175 );
 //     else servo1.write( command_data_value );
 
    } else if( command_name == 'V' ) { // command to vibratory dispenser

      if( command_data_value < 102 ) analogWrite( 45, 102 );  // safe max of 3 V to motor
      else if( command_data_value > 255 ) analogWrite( 45, 255 );
      else analogWrite( 45, command_data_value );

    }
  }
}

The Servo library uses 16-bit timers to time interrupts for the output pulses.

On the Uno there is just one 16 bit timer, timer1, and the Servo library uses that
which means PWM on pins 9 and 10 is not available as they are driven by timer1.

On the Mega the Servo libraries uses timer5, then timer1, timer3, timer4. Each timer
drives up to 12 servos so typically only timer5 is needed on the Mega, and timer5
generates PWM on pins 44, 45, 46.

Except Mark, that here it says this:

On the Mega, up to 12 servos can be used without interfering with PWM functionality

MarkT:
The Servo library uses 16-bit timers to time interrupts for the output pulses.

On the Uno there is just one 16 bit timer, timer1, and the Servo library uses that
which means PWM on pins 9 and 10 is not available as they are driven by timer1.

On the Mega the Servo libraries uses timer5, then timer1, timer3, timer4. Each timer
drives up to 12 servos so typically only timer5 is needed on the Mega, and timer5
generates PWM on pins 44, 45, 46.

Thanks.

Is the answer to just use one of pins 2-13 for my PWM needs, since they use a different timer? That'd be inconvenient since the motor shield occupies all of those connectors, and I haven't soldered on new connectors to go on the motor shield. But I guess I can do that. At some point I was going to put the voltage regulator I currently have breadboarded onto the open real estate on the motor shield ... easy enough to do it then.

Also, the reference states the Mega can do PWM on 14 pins: pins 2-13 and 44-46 ... I count 15 pins there, not 14. Am I missing something?

168gr:
Is the answer to just use one of pins 2-13 for my PWM needs, since they use a different timer?

It appears that this is the answer. I moved the PWM from 45 to 13 and now everything works.

Irritating, but I can live with it.

JimboZA:
Except Mark, that here it says this:

On the Mega, up to 12 servos can be used without interfering with PWM functionality

But I read the source code, and in variants/mega/pins_arduino.h pins 44 to 46 are
explicitly tagged as being PWM in the digital_pin_to_time_PGM array.

As far as I know the pins 44..46 are not marked on the Mega as "~", the PWM support is
not advertised, but it exists.

MarkT:
I read the source code

Well I guess that trumps the web page 8)

The web page probably never got updated, the code has probably changed since the
first Mega came out, the code is what runs on the thing, you have the source code in
the distribution, therefore it is the true documentation.

MarkT:
the source code ... is the true documentation.

Indeed it is...