Hi everyone! I need to drive a few servos and I almost despaired when I found out the hard way that the Servo library has not yet been rewritten for the Due.
But then I read about the Due hardware PWM support. Using the code below (or something similar) you can drive up to four servos without software overhead, using only the PWM clock.
It doesn't convert from angles to microsecond pulses but you can do that easily enough.
DueServo.h:
/**
* Hardware servo library. Available pins on the Arduino Due: 6, 7, 8, 9.
*/
#ifndef DUE_SERVO_H
#define DUE_SERVO_H
#include <Arduino.h>
#define PWM_DUTY_MIN 544
#define PWM_DUTY_MAX 2400
void writeMicros(int pin, uint16_t dutyCycle);
void initServo(int pin, uint16_t dutyCycle);
#endif
DueServo.cpp:
/**
* Hardware Servo library. Available pins on the Arduino Due: 6, 7, 8, 9
*/
#include "DueServo.h"
#define PWM_CLOCK 1000000
#define PWM_PERIOD 20000
static bool PWMEnabled = false;
void initServo(int pin, uint16_t dutyCycle) {
if(!PWMEnabled) {
pmc_enable_periph_clk(PWM_INTERFACE_ID);
PWMC_ConfigureClocks(PWM_CLOCK, 0, VARIANT_MCK);
PWMEnabled = true;
}
const PinDescription *config = &g_APinDescription[pin];
int channel = config->ulPWMChannel;
if(channel == NOT_ON_PWM)
return;
PIO_Configure(
config->pPort,
config->ulPinType,
config->ulPin,
config->ulPinConfiguration);
PWMC_ConfigureChannel(PWM_INTERFACE, channel, PWM_CMR_CPRE_CLKA, 0, 0);
PWMC_SetPeriod(PWM_INTERFACE, channel, PWM_PERIOD);
writeMicros(pin, dutyCycle);
PWMC_EnableChannel(PWM_INTERFACE, channel);
}
void writeMicros(int pin, uint16_t dutyCycle) {
int channel = g_APinDescription[pin].ulPWMChannel;
if(channel == NOT_ON_PWM)
return;
if(dutyCycle < PWM_DUTY_MIN)
dutyCycle = PWM_DUTY_MIN;
if(dutyCycle > PWM_DUTY_MAX)
dutyCycle = PWM_DUTY_MAX;
PWMC_SetDutyCycle(PWM_INTERFACE, channel, dutyCycle);
}
Sketch code, alternating the servo between two positions:
#include <Arduino.h>
#include <DueServo.h>
#define SERVO_PIN 6
bool high = false;
void setup() {
initServo(SERVO_PIN, 900);
}
void loop() {
high = !high;
writeMicros(SERVO_PIN, high?1200:900);
delay(500);
}
EDIT: better function names
EDIT2: correct #include<Arduino.h> in DueServo.h