adafruit / Adafruit_nRF52_Arduino

Adafruit code for the Nordic nRF52 BLE SoC on Arduino
Other
623 stars 497 forks source link

support Servo Libraries #68

Closed hathach closed 7 years ago

hathach commented 7 years ago

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

hathach commented 7 years ago

to many differences, It is easier to implement Servo with our own HardwarePWM :(

microbuilder commented 7 years ago

Anything that's compatible at the higher level API level is fine, I think.

hathach commented 7 years ago

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

hathach commented 7 years ago

the update code should work, though more tests should be carried out.

ichbtm commented 6 years ago

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...

hathach commented 6 years ago

@ichbtm thank you very much for your help, somehow this issue fall off our radar until recently :(