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)