Skip to content

Commit a3517bf

Browse files
committed
Servo can also use HwPWM ownership abstraction
1 parent 11d7b03 commit a3517bf

File tree

2 files changed

+70
-40
lines changed

2 files changed

+70
-40
lines changed

libraries/Servo/src/Servo.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ class Servo
101101
{
102102
public:
103103
Servo();
104-
uint8_t attach(int pin); // attach the given pin to the next free channel, sets pinMode, returns channel number or 0 if failure
104+
uint8_t attach(int pin); // attach the given pin to the next free channel, sets pinMode, returns channel number or INVALID_SERVO if failure (zero is a valid channel number)
105105
uint8_t attach(int pin, int min, int max); // as above but also sets min and max values for writes.
106106
void detach();
107107
void write(int value); // if value is < 200 its treated as an angle, otherwise as pulse width in microseconds

libraries/Servo/src/nrf52/Servo.cpp

Lines changed: 69 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <Arduino.h>
2222
#include <Servo.h>
2323

24+
static uintptr_t _servoToken = (uintptr_t)(&_servoToken);
2425

2526
static servo_t servos[MAX_SERVOS]; // static array of servo structures
2627
uint8_t ServoCount = 0; // the total number of attached servos
@@ -32,7 +33,6 @@ Servo::Servo()
3233
} else {
3334
this->servoIndex = INVALID_SERVO; // too many servos
3435
}
35-
3636
this->pwm = NULL;
3737
}
3838

@@ -43,55 +43,81 @@ uint8_t Servo::attach(int pin)
4343

4444
uint8_t Servo::attach(int pin, int min, int max)
4545
{
46-
if (this->servoIndex < MAX_SERVOS) {
47-
pinMode(pin, OUTPUT); // set servo pin to output
48-
servos[this->servoIndex].Pin.nbr = pin;
49-
50-
if (min < MIN_PULSE_WIDTH) min = MIN_PULSE_WIDTH;
51-
if (max > MAX_PULSE_WIDTH) max = MAX_PULSE_WIDTH;
52-
53-
//fix min if conversion to pulse cycle value is too low
54-
if((min/DUTY_CYCLE_RESOLUTION)*DUTY_CYCLE_RESOLUTION<min) min+=DUTY_CYCLE_RESOLUTION;
55-
56-
this->min = min;
57-
this->max = max;
58-
59-
servos[this->servoIndex].Pin.isActive = true;
60-
61-
// Adafruit, add pin to 1 of available Hw PWM
62-
for(int i=0; i<HWPWM_MODULE_NUM; i++)
63-
{
64-
if ( HwPWMx[i]->addPin(pin) )
65-
{
46+
if (this->servoIndex == INVALID_SERVO) {
47+
return INVALID_SERVO;
48+
}
49+
bool succeeded = false;
50+
pinMode(pin, OUTPUT); // set servo pin to output
51+
servos[this->servoIndex].Pin.nbr = pin;
52+
53+
if (min < MIN_PULSE_WIDTH) {
54+
min = MIN_PULSE_WIDTH;
55+
}
56+
if (max > MAX_PULSE_WIDTH) {
57+
max = MAX_PULSE_WIDTH;
58+
}
59+
60+
//fix min if conversion to pulse cycle value is too low
61+
if ( (min/DUTY_CYCLE_RESOLUTION) * DUTY_CYCLE_RESOLUTION < min) {
62+
min += DUTY_CYCLE_RESOLUTION;
63+
}
64+
65+
this->min = min;
66+
this->max = max;
67+
68+
servos[this->servoIndex].Pin.isActive = true;
69+
70+
// Adafruit, add pin to 1 of available Hw PWM
71+
// first, use existing HWPWM modules (already owned by Servo)
72+
for(int i=0; i<HWPWM_MODULE_NUM; i++) {
73+
if (HwPWMx[i]->isOwner(_servoToken) &&
74+
HwPWMx[i]->addPin(pin)) {
75+
this->pwm = HwPWMx[i];
76+
succeeded = true;
77+
break;
78+
}
79+
}
80+
// if could not add to existing owned PWM modules, try to add to a new PWM module
81+
if (!succeeded) {
82+
for(int i=0; i<HWPWM_MODULE_NUM; i++) {
83+
if (HwPWMx[i]->takeOwnership(_servoToken) &&
84+
HwPWMx[i]->addPin(pin)) {
6685
this->pwm = HwPWMx[i];
86+
succeeded = true;
6787
break;
6888
}
6989
}
90+
}
7091

92+
if (succeeded) { // do not use this->pwm unless success above!
7193
this->pwm->setMaxValue(MAXVALUE);
7294
this->pwm->setClockDiv(CLOCKDIV);
73-
7495
}
75-
return this->servoIndex;
96+
return succeeded ? this->servoIndex : INVALID_SERVO; // return INVALID_SERVO on failure (zero is a valid servo index)
7697
}
7798

7899
void Servo::detach()
79100
{
80-
uint8_t const pin = servos[this->servoIndex].Pin.nbr;
81-
82-
servos[this->servoIndex].Pin.isActive = false;
101+
if (this->servoIndex == INVALID_SERVO) {
102+
return;
103+
}
83104

84-
// remove pin from HW PWM
85-
this->pwm->removePin(pin);
105+
uint8_t const pin = servos[this->servoIndex].Pin.nbr;
106+
servos[this->servoIndex].Pin.isActive = false;
107+
// remove pin from HW PWM
108+
HardwarePWM * pwm = this->pwm;
109+
this->pwm = nullptr;
110+
pwm->removePin(pin);
111+
pwm->releaseOwnership(_servoToken); // ignore failure ... which happens if a pin is still in use, for example
86112
}
87113

88-
89114
void Servo::write(int value)
90-
{
91-
if (value < 0)
115+
{
116+
if (value < 0) {
92117
value = 0;
93-
else if (value > 180)
118+
} else if (value > 180) {
94119
value = 180;
120+
}
95121
value = map(value, 0, 180, this->min, this->max);
96122

97123
writeMicroseconds(value);
@@ -100,9 +126,10 @@ void Servo::write(int value)
100126

101127
void Servo::writeMicroseconds(int value)
102128
{
103-
uint8_t pin = servos[this->servoIndex].Pin.nbr;
104-
105-
if ( this->pwm ) this->pwm->writePin(pin, value/DUTY_CYCLE_RESOLUTION);
129+
if (this->pwm) { // pwm is only set when this->servoIndex != INVALID_SERVO
130+
uint8_t pin = servos[this->servoIndex].Pin.nbr;
131+
this->pwm->writePin(pin, value/DUTY_CYCLE_RESOLUTION);
132+
}
106133
}
107134

108135
int Servo::read() // return the value as degrees
@@ -112,15 +139,18 @@ int Servo::read() // return the value as degrees
112139

113140
int Servo::readMicroseconds()
114141
{
115-
uint8_t pin = servos[this->servoIndex].Pin.nbr;
116-
117-
if ( this->pwm ) return this->pwm->readPin(pin)*DUTY_CYCLE_RESOLUTION;
118-
142+
if (this->pwm) { // pwm is only set when this->servoIndex != INVALID_SERVO
143+
uint8_t pin = servos[this->servoIndex].Pin.nbr;
144+
return this->pwm->readPin(pin)*DUTY_CYCLE_RESOLUTION;
145+
}
119146
return 0;
120147
}
121148

122149
bool Servo::attached()
123150
{
151+
if (this->servoIndex == INVALID_SERVO) {
152+
return false;
153+
}
124154
return servos[this->servoIndex].Pin.isActive;
125155
}
126156

0 commit comments

Comments
 (0)