Pololu Robotics & Electronics
Menu
My account Comments or questions? About Pololu Contact Ordering information Distributors

Pololu Forum

Possible bug in Dual VNH5019 Motor Driver Shield Library

Hi guys,

I think I might have found a small bug in the VNH5019 Dual Motor Driver Shield library at https://github.com/pololu/dual-vnh5019-motor-shield.

To correctly generate a 20kHz PWM frequency, the Timer1 TOP is being set at 400 here:

  // PWM frequency calculation
  // 16MHz / 1 (prescaler) / 2 (phase-correct) / 400 (top) = 20kHz
  TCCR1A = 0b10100000;
  TCCR1B = 0b00010001;
  ICR1 = 400;

However the methods that write values to the PWM outputs via analogWrite are scaling them back to 255 (speed*51/80) when using larger Arduinos such as the Mega2560:

// Set speed for motor 1, speed is a number betwenn -400 and 400
void DualVNH5019MotorShield::setM1Speed(int speed)
{
  unsigned char reverse = 0;
  
  if (speed < 0)
  {
    speed = -speed;  // Make speed a positive quantity
    reverse = 1;  // Preserve the direction
  }
  if (speed > 400)  // Max PWM dutycycle
    speed = 400;
  #if defined(__AVR_ATmega168__)|| defined(__AVR_ATmega328P__) || defined(__AVR_ATmega32U4__)
  OCR1A = speed;
  #else
  analogWrite(_PWM1,speed * 51 / 80); // default to using analogWrite, mapping 400 to 255
  #endif

This scaling means that using this library on a Mega2560 when you use md.setM1Speed() from 0 to 399 the PWM duty cycle actually ranges from 0% to ~64% (399*51/80 = 254 out of 400), and then suddenly skips to 100% if you use md.setM1Speed(400) since analogWrite internally outputs a HIGH state when it receives 255 as value.

None of that happens using an UNO, since the PWM writing is being done thru OCR1A instead of analogWrite. But if we comment out the #if defined(AVR_ATmega168)|| defined(AVR_ATmega328P) || defined(AVR_ATmega32U4) lines and force usage of analogWrite even on the UNO, the same behavior is verified.

If we try the following sequence (PWM for M1 is on pin 9 on this shield):

  analogWrite(9, 254);
  delay(1000);  
  analogWrite(9, 255);
  delay(1000);  
  analogWrite(9, 256);
  delay(1000);

the resulting square waves have duty cycles of ~63%, 100% and ~64% respectively.

If anybody else in possession of this shield and a scope could confirm this behavior, I’d be glad to hear.

Cheers,
Fowler

EDIT: To whom it may concern, I made a small Excel sheet to try to sort some sense out of the complete and utter mess that are timer control registers on the AVR, attachment follows.
TCCRxy.xlsx (14.5 KB)

Hello, Fowler.

[quote=“rbfowler9”] analogWrite(9, 254); delay(1000); analogWrite(9, 255); delay(1000); analogWrite(9, 256); delay(1000);

the resulting square waves have duty cycles of ~63%, 100% and ~64% respectively.[/quote]

I tried using an Arduino Mega and our VNH5019 shield with the dual-vnh5019-motor-shield library and did not get the same results you did. For analogWrite(9, 254), I observed a PWM signal with 99.6% duty cycle at 980 Hz, and analogWrite(9, 256) did not produce a signal. What were you measuring when you got those results? If you have not already, could you try running the code above without including our library and see if you still observe the same signals on pin 9?

By the way, you can find a modified version of the VNH5019 shield library for the Arduino Mega that drive motors with a 20 kHz PWM in this thread.

- Jeremy

Hi, Fowler.

The library should not touch the Timer1 configuration registers on a Mega2560, since there is another #ifdef before those lines you quoted (see line 48 in DualVNH5019MotorShield.cpp):

  #if defined(__AVR_ATmega168__)|| defined(__AVR_ATmega328P__) || defined(__AVR_ATmega32U4__)
  // Timer 1 configuration
  // prescaler: clockI/O / 1
  // outputs enabled
  // phase-correct PWM
  // top of 400
  //
  // PWM frequency calculation
  // 16MHz / 1 (prescaler) / 2 (phase-correct) / 400 (top) = 20kHz
  TCCR1A = 0b10100000;
  TCCR1B = 0b00010001;
  ICR1 = 400;
  #endif

So the range of motor speeds should remain at the default analogWrite range of 0-255. If you are actually seeing the problematic behavior you described, could you tell us more about what you are doing and how you observed the result?

- Kevin

Hi Kevin and Jeremy,

I’ll be out of town for the whole weekend, so my hardware is out of reach right now.

Having second thoughts on what Kevin said, I think I might have unwittingly messed something up, as I tested on both an Uno R3 and a Mega 2560, but I remember observing a 20kHz signal on both of them, using the standard lib on GitHub found on the resources tab of the product page. I’ll redownload the lib, rebuild my sketches and ckeck back to you on monday.

Thanks for the prompt support and excellent hardware guys!

Hi guys,

Been busy as hell, just a quick follow up, after reviewing all my code I found out it was really my mistake, as I had modified the original library to use Timer3 (being unaware that a modded version using T3 was already available), and I ended up commenting some #defines I should have paid more attention to.

Now everything is settled, thanks for the prompt replies and sorry for the mixup.

Fowler

I am glad you found the issue. Thanks for letting us know.

- Jeremy