Closed hathach closed 7 years ago
to many differences, It is easier to implement Servo with our own HardwarePWM :(
Anything that's compatible at the higher level API level is fine, I think.
the hardware PWM works fine, we just need to to wrap it up with the servo API and have some tests to make sure it works. I am finding those little servo to hook up :D
the update code should work, though more tests should be carried out.
Don't know if I post at the right place. Your implementation use hardcoded pulse limits and doesn't use user values given to the attach function. More, input of writeMicroseconds is not a µs value. Maybe the following modifications should be nice ?
Servo.h :
//---convert int8_t to int16_t to be able to store a pulse width
int16_t min; // minimum pulse µs
int16_t max; // maximum pulse µs
servoTimers.h :
//---suppress hardcoded duty cycle values
//#define MIN_PULSE 55
//#define MAX_PULSE 284
//---add some named constants for clarity
//PWM_PRESCALER_PRESCALER_DIV_128 -> NRF_PWM_CLK_125kHz -> resolution 8µs
//MaxValue = 2500 -> PWM period = 20ms
//20ms - 50Hz
#define RESOLUTION 8
#define MAXVALUE 2500
#define CLOCKDIV PWM_PRESCALER_PRESCALER_DIV_128
Servo.cpp :
//--- use Servo.h limits by default
uint8_t Servo::attach(int pin) {
return this->attach(pin, MIN_PULSE_WIDTH, MAX_PULSE_WIDTH);
}
//--- use Servo.h limits and store user ones in structure
uint8_t Servo::attach(int pin, int min, int max) {
if (this->servoIndex < MAX_SERVOS) {
pinMode(pin, OUTPUT); // set servo pin to output
servos[this->servoIndex].Pin.nbr = pin;
if(min < MIN_PULSE_WIDTH) min = MIN_PULSE_WIDTH;
if (max > MAX_PULSE_WIDTH) max = MAX_PULSE_WIDTH;
this->min = min;
this->max = max;
servos[this->servoIndex].Pin.isActive = true;
// Adafruit, add pin to 1 of available Hw PWM
for(int i=0; i<HWPWM_MODULE_NUM; i++) {
if ( HwPWMx[i]->addPin(pin) ) {
HwPWMx[i]->setMaxValue(MAXVALUE);
HwPWMx[i]->setClockDiv(CLOCKDIV);
break;
}
}
}
return this->servoIndex;
}
//---use user limits in µs instead of hardcoded values
void Servo::write(int value) {
if (value < 0)
value = 0;
else if (value > 180)
value = 180;
value = map(value, 0, 180, this->min, this->max);
writeMicroseconds(value);
}
//---use µs as input value instead of duty cycle value
void Servo::writeMicroseconds(int value) {
uint8_t pin = servos[this->servoIndex].Pin.nbr;
for(int i=0; i<HWPWM_MODULE_NUM; i++) {
if ( HwPWMx[i]->writePin(pin, value/RESOLUTION) ) break;
}
}
Another problem I found is that sometimes the PWM signal is inverted. But I have no other solutions than chaining two attach, detach sequence...
@ichbtm thank you very much for your help, somehow this issue fall off our radar until recently :(
Standard Servo Libraries is already ported to work with nrf52 on Primo board https://github.com/arduino-libraries/Servo/tree/master/src/nrf52
It is based on several Nordic peripheral driver in SDK which we lack ( due to restricted license). https://github.com/arduino-org/arduino-core-nrf52/tree/master/cores/arduino/components
However since the latest sdk 13 open the license to BSD like. We could include those and get the Servo support